[BalticOI 2014 Day1] Three Friends
题目描述
有一个字符串 S S S,对他进行操作:
- 将 S S S 复制为两份,存在字符串 T T T 中
- 在 T T T 的某一位置上插入一个字符,得到字符串 U U U
现在给定 U U U,求 S S S。
输入格式
第一行一个整数
N
N
N 代表
U
U
U 的长度。
第二行
N
N
N 个字符代表字符串
U
U
U。
输出格式
- 如果不能通过上述的步骤从
S
S
S 推到
U
U
U,输出
NOT POSSIBLE
。 - 如果从
U
U
U 得到的
S
S
S 不是唯一的,输出
NOT UNIQUE
。 - 否则,输出一个字符串 S S S。
样例 #1
样例输入 #1
7
ABXCABC
样例输出 #1
ABC
样例 #2
样例输入 #2
6
ABCDEF
样例输出 #2
NOT POSSIBLE
样例 #3
样例输入 #3
9
ABABABABA
样例输出 #3
NOT UNIQUE
提示
数据规模与约定
本题采用捆绑测试。
- Subtask 1(35 pts): N ≤ 2001 N \le 2001 N≤2001。
- Subtask 2(65 pts):无特殊限制。
对于 100 % 100\% 100% 的数据, 2 ≤ N ≤ 2 × 1 0 6 + 1 2 \le N \le 2 \times 10^6+1 2≤N≤2×106+1,保证 U U U 中只包含大写字母。
说明
翻译自 BalticOI 2014 Day1 B Three Friends。
大致思路
首先一个很显然的结论:由于 U 串是 S 串复制两次后插入一个字符所得,因此长度必然为奇数。所以特判:若 n 为偶数则直接输出 NOT POSSIBLE。
接下来,将得到的字符串分成两部分 1∼mid, mid+1∼n,并分别记录这两段的哈希值。然后对于 mid+1∼n,枚举删去 1∼mid 中的字符,若所得字符串与后半段相等则答案数 ans+1 并跳出循环。反之亦然。
inline unsigned long long check(int l, int r) {
return h[r]-h[l-1]*pre[r-l+1];
}//区间哈希值
inline unsigned long long sum(int l, int r, int k) {
return check(l,k-1)*pre[r-k]+check(k+1,r);
}//删去字符
l1=check(mid+1,n);
for(int i=mid+1;i<=n;i++)
a.push_back(s[i]);
for(int i=1;i<=mid;i++){
l2=sum(1,mid,i);
if (l1==l2){
ans++;
c=a;
break;
}
}
l2=check(1,mid-1);
for(int i=1;i<mid;i++)
b.push_back(s[i]);
for(int i=mid;i<=n;i++){
l1=sum(mid,n,i);
if(l1==l2) {
ans++;
d=b;
break;
}
}//枚举
然后进行判断:
-
若答案数为零,则无解,输出 NOT POSSIBLE。
-
若答案数为一,或删去字符后的两串相等,则输出删去后不为空的字符串(即所求的 S)。
-
否则说明答案不唯一,输出 NOT UNIQUE。
AC CODE
#include<bits/stdc++.h>
using namespace std;
#define maxn 2000002
string a, b, c, d;
int n, mid, l1, l2, h[maxn], pre[maxn], ans;
char s[maxn];
inline unsigned long long check(int l, int r) {
return h[r]-h[l-1]*pre[r-l+1];
}//区间哈希值
inline unsigned long long sum(int l, int r, int k) {
return check(l,k-1)*pre[r-k]+check(k+1,r);
}//删去字符
int main(){
scanf("%d%s",&n,s+1);
mid=(n+1)>>1;
if (n%2==0){
cout<<"NOT POSSIBLE";
return 0;
}//特判
pre[0]=1;
for(int i= 1;i<=n;i++){
pre[i]=pre[i-1]*10007;
h[i]=h[i-1]*10007+(s[i]-'A'+1);
}//预处理
l1=check(mid+1,n);
for(int i=mid+1;i<=n;i++)
a.push_back(s[i]);
for(int i=1;i<=mid;i++){
l2=sum(1,mid,i);
if (l1==l2){
ans++;
c=a;
break;
}
}
l2=check(1,mid-1);
for(int i=1;i<mid;i++)
b.push_back(s[i]);
for(int i=mid;i<=n;i++){
l1=sum(mid,n,i);
if(l1==l2) {
ans++;
d=b;
break;
}
}//枚举
if(!ans)
cout<<"NOT POSSIBLE";
else if(ans==1||c==d){
if(c.size()==0)cout<<d;
else cout<<c;
}
else cout<<"NOT UNIQUE";//判断输出
return 0;
}