题目描述
本题译自 BalticOI 2014 Day1 T2「Three Friends」
给定一个字符串 S,先将字符串 S 复制一次(变成双倍快乐),得到字符串 T,然后在 T 中插入一个字符,得到字符串 U。
给出字符串 U,重新构造出字符串 S。
所有字符串只包含大写英文字母。
输入格式
第一行一个整数 N,表示字符串 U 的长度。
第二行一个长度为 N 的字符串,表示字符串 U。
输出格式
一行一个字符串,表示字符串 S。
特别地:
如果字符串无法按照上述方法构造出来,输出 NOT POSSIBLE
;
如果字符串 S 不唯一,输出 NOT UNIQUE
。
样例 1
输入
1 7
2 ABCXABC
输出
1 ABC
样例 2
输入
1 6
2 ABCDEF
输出
1 NOT POSSIBLE
样例 3
输入
1 9
2 ABABABABA
输出
1 NOT UNIQUE
数据范围与提示
2 < = n < = 20000002 2<=n<=20000002 2<=n<=20000002
ACcode
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
char s[20000009];
string r_s1,r_s2,l_s1,l_s2;//r_s1 l_s1表示处理前字符串U的右半段和左半段,r_s2 l_s2表示删去字符后的右半段和左半段
int n,b=1311,r_Hash,l_Hash,ans;//r_Hash表示字符串U右半段的哈希值,l_Hash表示左半段的哈希值
ULL poww[20000009],Hash[20000009];
ULL _Hash(int l,int r)
{
return Hash[r]-Hash[l-1]*poww[r-l+1];
}//求指定区域的哈希值
ULL del(int l,int r,int k)
{
return _Hash(l,k-1)*poww[r-k]+_Hash(k+1,r);
}//删去第k个字符,重新求哈希值
int main()
{
cin>>n;
poww[0]=1;
for(int i=1;i<=n;i++)
poww[i]=poww[i-1]*b;//预处理
scanf("%s",s+1);
if(n%2==0)//特判,n的长度必为奇数,因为字符串U是由一个字符串复制两次插入一个字符得到的
{
cout<<"NOT POSSIBLE";
return 0;
}
int mid=(n+1)/2;
for(int i=1;i<=n;i++)
Hash[i]=Hash[i-1]*b+(ULL)(s[i]-'A'+1);//预处理
r_Hash=_Hash(mid+1,n);//求右半段哈希值
for(int i=mid+1;i<=n;i++)
r_s1.push_back(s[i]);
for(int i=1;i<=mid;i++)//左半段依次删去第i个字符,与右半段比较
{
l_Hash=del(1,mid,i);
if(l_Hash==r_Hash)//左右半段相同
{
ans++;//答案+1
r_s2=r_s1;//记录处理后的右半段
break;
}
}
l_Hash=_Hash(1,mid-1);//求左半段哈希值
for(int i=1;i<mid;i++)
l_s1.push_back(s[i]);
for(int i=mid;i<=n;i++)//右半段依次删去第i个字符,与左半段比较,循环内容同上
{
r_Hash=del(mid,n,i);
if(r_Hash==l_Hash)
{
ans++;
l_s2=l_s1;
break;
}
}
if(ans==0) cout<<"NOT POSSIBLE";//没有答案
else
if(ans==1||r_s2==l_s2)
{
if(r_s2.size()==0) cout<<l_s2;
else cout<<r_s2;
}//输出处理后不为空的半段,即是答案
else cout<<"NOT UNIQUE";//有多个答案
return 0;
}
思路:
首先将字符串U分为1 ~ mid-1 和 mid+1 ~ n,分别求出这两段的哈希值(l_Hash和r_Hash),然后枚举右段mid~n,依次删去第i个字符,求出删去第i个字符后这一段的哈希值,与l_Hash比较,若相同,ans++
1.特判
if(n%2==0)
{
cout<<"NOT POSSIBLE";
return 0;
}
n的长度一定为奇数,因为字符串U是由一个字符串复制两次插入一个字符得到的,若n为偶数,直接输出 NOT POSSIBLE
,然后return 0
2.两个函数
ULL _Hash(int l,int r)
{
return Hash[r]-Hash[l-1]*poww[r-l+1];
}
ULL del(int l,int r,int k)
{
return _Hash(l,k-1)*poww[r-k]+_Hash(k+1,r);
}
①_Hash函数是用来求 左端点为 l,右端点为 r 的子串的哈希值
②del函数是删去第k个字符后,用来求 左端点为 l,右端点为 r 的子串的哈希值
3.输出
if(ans==0) cout<<"NOT POSSIBLE";
else
if(ans==1||r_s2==l_s2)
{
if(r_s2.size()==0) cout<<l_s2;
else cout<<r_s2;
}
else cout<<"NOT UNIQUE";
①如果没有答案,输出NOT POSSIBLE
②否则:如果有一个答案 或者 两个串删去字符后相等 输出非空的串
③最后:有多个答案,输出 NOT UNIQUE