题面
【题目描述】
有三个好朋友喜欢在一起玩游戏,A君写下一个字符串S,B君将其复制一遍得到T,C君在T的任意位置(包括首尾)插入一个字符得到U.现在你得到了U,请你找出S.
【输入】
第一行一个数N,表示U的长度.
第二行一个字符串U,保证U由大写字母组成
【输出】
输出一行,若S不存在,输出"NOT POSSIBLE".若S不唯一,输出"NOT UNIQUE".否则输出S.
【样例输入】
7
ABCXABC
【样例输出】
ABC
【数据范围】
对于100%的数据 2<=N<=2000001
算法分析
字符串Hash
根据题意,直接模拟即可。
枚举插入的字符,判断剩下的字符串分成两部分后是否相同即可,枚举时需要判断不同情况,且需要注意子串是否唯一。判断相等时间复杂度O(1),总时间复杂度为O(N)。
参考程序
106
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define b 31
#define N 2000100
using namespace std;
unsigned int ha[N],p[N],n,ha1=0;
char s1[N];
bool check(int x,int y) //判断找到的子串是否一致(如AAAAA,可以在任何地方插入,但子串唯一AA)
{
int t;
if(ha1)
{
t=ha[y]-ha[x-1]*p[y-x+1];
if(t!=ha1) return 1; //不唯一返回1
else return 0;
}
else
{
ha1=ha[y]-ha[x-1]*p[y-x+1]; //记录找到的字符串的Hash值
return 1;
}
}
int main()
{
p[0]=1;
for(int i=1;i<=N;i++) //预处理b的次方
p[i]=p[i-1]*b;
scanf("%d %s",&n,s1);
ha[0]=s1[0]-'A'+1;
for(int i=1;i<n;i++) //字符串前缀hash
ha[i]=ha[i-1]*b+(s1[i]-'A'+1);
// for(int i=0;i<n;i++)
// cout<<ha[i]<<" ";
// cout<<endl;
int ans=0,w;
if(n%2==0) {printf("NOT POSSIBLE\n");return 0;} //偶数无解
if((ha[n/2]-ha[0]*p[n/2])==(ha[n-1]-ha[n/2]*p[n/2])) { if(check(1,n/2)) {ans++;w=0;} } //在首位插入
// cout<<ha[n/2-1]<<" "<<ha[n-2]-ha[n/2-1]*p[n/2]<<" ";
if(ha[n/2-1]==(ha[n-2]-ha[n/2-1]*p[n/2])) {if(check(0,n/2-1)) {ans++;w=n-1;}} //在尾插入
if(ha[n/2-1]==(ha[n-1]-ha[n/2]*p[n/2])) {if(check(0,n/2-1)) {ans++;w=n/2;}} //在中间插入
for(int k=1;k<n/2;k++) //在左半部分插入
{
unsigned int t1=ha[k-1]*p[n/2-k]+ha[n/2]-ha[k]*p[n/2-k];
unsigned int t2=ha[n-1]-ha[n/2]*p[n/2];
// cout<<t1<<" "<<t2<<endl;
if(t1==t2&&check(n/2+1,n-1))
{
ans++;w=k;
}
}
for(int k=n/2+1;k<n-1;k++) //在右半部分插入
{
unsigned int t1=ha[n/2-1];
unsigned int t2=(ha[k-1]-ha[n/2-1]*p[k-n/2])*p[n-k-1]+(ha[n-1]-ha[k]*p[n-k-1]);
// cout<<t1<<" "<<t2<<endl;
if(t1==t2&&check(0,n/2-1))
{
ans++;w=k;
}
}
if(ans==0) printf("NOT POSSIBLE\n");
else if(ans>1) printf("NOT UNIQUE\n");
else
{
if(w==0)
{
for(int i=1;i<=n/2;i++)
printf("%c",s1[i]);
}
else if(w==n-1)
{
for(int i=0;i<n/2;i++)
printf("%c",s1[i]);
}
else if(w==n/2)
{
for(int i=0;i<n/2;i++)
printf("%c",s1[i]);
}
else if(w<n/2)
{
for(int i=0;i<=n/2;i++)
if(i==w) continue;
else printf("%c",s1[i]);
}
else
{
for(int i=0;i<n/2;i++)
printf("%c",s1[i]);
}
}
return 0;
}