联考20200730 T2 小B的环



分析:
考虑删除哪些不好做,我们考虑留下哪些
由于删除的是环上一段,那么留下的也是环上一段
首先已经相邻的不能算在其中了
假设有相邻的,我们以这个位置切开,得到许多合法的子串
假设其中一个子串长度为(L)
我们考虑这个子串还能不能再删除得到一个新的长度(l)
如果一个长度(l)无解,即在这个子串中(S_i=S_{i+l})恒成立
发现这个就是一个字符串的border
那么进行一次KMP,递归求解就好了
如果最开始就没有相邻的,直接把串翻倍做KMP就好了
复杂度(O(n))

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>

#define maxn 10000005

using namespace std;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n;
char ans[maxn],s[maxn];
int p[maxn],cnt;
int fail[maxn];

inline void solve(char *a,int len)
{
	fail[1]=0;
	for(int i=2;i<=len;i++)
	{
		int j=fail[i-1];
		while(j&&a[i]!=a[j+1])j=fail[j];
		if(a[i]==a[j+1])j++;fail[i]=j;
	}
	int now=len,lst=1;
	while(now)
	{
		for(int i=lst;i<=len-fail[now];i++)if(i<n)ans[n-i]='1';
		lst=len-(now=fail[now])+2;
	}
}

int main()
{
	while(~scanf("%s",s+1))
	{
		n=strlen(s+1);
		if(n==1){puts("0");continue;}
		for(int i=0;i<n;i++)ans[i]='0';cnt=0;
		for(int i=1;i<=n;i++)s[i+n]=s[i];
		for(int i=1;i<=n;i++)if(s[i]==s[i+1])p[++cnt]=i;
		if(cnt)ans[0]='0',p[++cnt]=p[1]+n;else ans[0]='1';
		for(int i=0;i<cnt;i++)solve(s+p[i],p[i+1]-p[i]);
		if(!cnt)solve(s,2*n);
		ans[n-1]='0',ans[n]=0;
		puts(ans);
	}
}

原文地址:https://www.cnblogs.com/Darknesses/p/13405788.html