题目描述
Description
String专题又出现啦~(≧▽≦)/~ 这次的题很水的啦0.0
一个字符串的子串是该字符串的一段连续子序列,如bca是abcabc的子串,而cc不是。
一个重复块(repeating block)由一个字符串与自身连接而成,如abcabc是一个重复块,而abcabd, ababab不是。
你有一个由拉丁字符组成的字符串。每一步你要找到它的子串中最短的重复块,如果有多于一个,你必须选择最左边的那个。你要将那个形如XX(X - 某个字符串)的重复块替换成X,换句话说你要删除其中的一个X。重复以上步骤直到字符串中不存在重复块。
最终的字符串会是怎样的?看样例解释来更清楚地理解问题描述。
Input
一行,一个由小写拉丁字符组成的字符串S。
Output
输出做完所有操作后的字符串。
Sample Input
aaaabaaab
Sample Output
ab
Data Constraint
对于10%的数据|S|<=10。
对于30%的数据|S|<=1000。
对于100%的数据1<=|S|<=50000。
10%
不会
似乎可以暴力构造(
26n
26
n
)+判断或者写30%常数比LCT还大
30~90%
暴力
每次找到重复块就删
可以多次计算发现每次找到的字符串长度不减
时间复杂度
O(n3)
O
(
n
3
)
写得特别优美可以拿90分(本人55)
100%
暴力+限制长度(500左右)
具体可以看这位兄♂弟
https://blog.csdn.net/enjoy_pascal/article/details/79678884
真·100%
经典套路
因为找到的是一个长为2L的字符串,所以可以每L位设一个观察点,则该串一定穿过相邻两个点
然后每相邻两个观察点之间求最长前/后缀
那么一个合法的串一定是这样的
可以这样构出一个合法串
设前缀长a,后缀长b,那么合法串一定是a+b>l的串
判断串相同就用哈希,为了准确可以用双哈希
每次字符串变化后重构,可以证明出时间复杂度是
O(|S|1.5+|S|log2|S|)
O
(
|
S
|
1.5
+
|
S
|
log
2
|
S
|
)
然而我不会证
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#define mod 1000000007
#define Mod 100000007
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;
char st[50010];
char St[50010];
long long hash[50010];
long long Hash[50010];
long long p[50010];
long long P[50010];
int b[50010];
int c[50010];
int i,j,k,l,r,mid,L,n,N,len,last,I,J,K,bg;
bool Bz;
long long get(int x,int y)
{
long long ans=(hash[y]-hash[x-1]*p[y-x+1])%mod;
if (ans<0) ans+=mod;
return ans;
}
long long Get(int x,int y)
{
long long ans=(Hash[y]-Hash[x-1]*P[y-x+1])%Mod;
if (ans<0) ans+=Mod;
return ans;
}
int main()
{
scanf("%s",st);
len=strlen(st);
p[0]=1,P[0]=1;
fo(i,1,len)
p[i]=(p[i-1]*26)%mod,P[i]=(P[i-1]*26)%Mod;
Bz=1;
fo(L,1,strlen(st))
{
N=-1;
len=strlen(st);
if (Bz)
{
hash[0]=0;
Hash[0]=0;
fo(i,1,len)
{
hash[i]=(hash[i-1]*26+(st[i-1]-'a'))%mod;
Hash[i]=(Hash[i-1]*26+(st[i-1]-'a'))%Mod;
}
Bz=0;
}
bg=L;
fo(i,1,len/L-1)
{
j=i*L;
k=j+L;
l=0,r=min(L-1,bg);
while (l<r)
{
mid=(l+r)/2;
if ((get(j-mid,j)==get(k-mid,k)) && (Get(j-mid,j)==Get(k-mid,k)))
l=mid+1; else r=mid;
}
if ((get(j-l,j)!=get(k-l,k)) && (Get(j-l,j)!=Get(k-l,k))) l--;
b[i]=l;
l=0,r=min(L-1,len-k);
while (l<r)
{
mid=(l+r)/2;
if ((get(j,j+mid)==get(k,k+mid)) && (Get(j,j+mid)==Get(k,k+mid)))
l=mid+1; else r=mid;
}
if ((get(j,j+l)!=get(k,k+l)) || (Get(j,j+l)!=Get(k,k+l))) l--;
c[i]=l;
if (b[i]+c[i]+1>=L)
{
bg=k-(j-b[i]+L);
Bz=1;
}
else
bg=L;
}
if (!Bz)
continue;
last=1;
fo(i,1,len/L-1)
{
j=i*L;
k=j+L;
if (b[i]+c[i]+1>=L)
{
fo(I,last,j-b[i]+L-1)
St[++N]=st[I-1];
last=j-b[i]+(L<<1);
}
}
fo(I,last,len)
St[++N]=st[I-1];
if (Bz)
{
memset(st,0,sizeof(st));
fo(i,0,N)
st[i]=St[i];
}
}
printf("%s\n",st);
return 0;
}
后记
谴责辣鸡出题人