三个朋友
https://loj.ac/problem/2823
题目描述
给出一个字符串\(U\),求满足条件的字符串\(S\)使其复制一遍再插入一个字符后的字符串为\(U\)。
思路
由于插入过一个字符,所以我们可以进行一次扫描,每次扫描时将这个字符去掉,把去掉后字符串分成长度相等的两段,再比较这两段是否完全相同即可。如果暴力枚举看是否相同肯定会\(T\)飞,我们考虑使用字符串\(Hash\),求出两段的\(Hash\)值比较是否相等即可。需要注意的有两点:\(①\)把字符串取出时注意对进制转换;\(②\)有可能会存在多个相等的\(S\),它们不算重复。
代码
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const ull p=47;
char s[2000005];
ull sum[2000005],power[2000005];
int main()
{
// freopen("aa.txt","r",stdin);
int n;
scanf("%d",&n);
scanf(" %s",s+1);
if(n%2==0){printf("NOT POSSIBLE");return 0;}
int len=(n-1)/2;
power[0]=1;
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]*p+s[i]-'A';
power[i]=power[i-1]*p;
}
ull ans=0,k=0,l=0;
bool f=1;
// cout<<sum[4]<<endl;
for(int i=1;i<=n;i++)
{
if(i<=len+1)
{
ull s1=sum[i-1]*power[len-i+1]+(sum[len+1]-sum[i]*power[len-i+1]);
ull s2=sum[n]-sum[n-len]*power[len];
if(s1==s2)
{
ans++;
if(ans==1)k=s1,l=i;
else if(k!=s1)f=0;
}
// cout<<i<<' '<<s1<<' '<<s2<<' '<<ans<<endl;
}
else
{
ull s1=sum[len];
ull s2=(sum[i-1]-sum[len]*power[i-len-1])*power[len*2-i+1]+sum[n]-sum[i]*power[n-i];
if(s1==s2)
{
ans++;
if(ans==1)k=s1,l=i;
else if(k!=s1)f=0;
}
// cout<<i<<' '<<s1<<' '<<s2<<' '<<ans<<endl;
}
}
// cout<<ans<<' '<<l<<endl;
if(ans==1||(ans>1&&f))
{
if(l<=len+1)
for(int i=n-len+1;i<=n;i++)
putchar(s[i]);
else
for(int i=1;i<=len;i++)
putchar(s[i]);
}
else if(ans==0)
printf("NOT POSSIBLE");
else printf("NOT UNIQUE");
return 0;
}