题解 P6739 【[BalticOI 2014 Day1] Three Friends】
Mars_Dingdang · · 题解
这一题用哈希就可以水掉了。需掌握求一个字符串区间哈希值的做法。
题目大意
尊重原题:有
简化版:有一个字符串
- 将
S 复制为两份,存在字符串T 中; - 在
T 的某一位置上插入一个字符,得到字符串U 。
现在给定
大体思路
前置芝士:字符串哈希
如果对字符串哈希不甚了解,请自行参考 这题。
此处介绍的,即是最常见的一种哈希:进制哈希。进制哈希的核心便是给出一个固定进制
首先选择两个质数。我选择 unsigned long long 自然溢出的特性作为模数。下方所有变量未经特殊说明均为无符号长整形。(详见代码)
接下来进行预处理:用一个数组
pre[0]=1;//边界条件:base 的 0 次方等于一。
for(int i= 1;i<=n;i++) {
pre[i]=pre[i-1]*22783;//记录 pre 数组
h[i]=h[i-1]*22783+(s[i]-'A'+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);
}//删去第 k 个字符
本题详解
首先一个很显然的结论:由于 NOT POSSIBLE。
接下来,将得到的字符串分成两部分
然后进行判断:
-
若答案数为零,则无解,输出
NOT POSSIBLE。 -
若答案数为一,或删去字符后的两串相等,则输出删去后不为空的字符串(即所求的
S )。 -
否则说明答案不唯一,输出
NOT UNIQUE。
完整代码
#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&1)){
printf("NOT POSSIBLE");
return 0;
}//特判
pre[0]=1;
for(int i= 1;i<=n;i++) {
pre[i]=pre[i-1]*22783;
h[i]=h[i-1]*22783+(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)
printf("NOT POSSIBLE");
else if (ans == 1 || c == d)
cout << (c.size() ? c : d);
else printf("NOT UNIQUE");//判断输出
return 0;
}
后记
今天 CSP2020 出成绩,普及组正常 1=,提高组因为 T3 加了 ios::sync_with_stdio(0); 语句而抱灵,导致 1= 没了,悲痛。
希望 NOIp rp++!