字符串哈希-friends-HYSBZ - 3916
题意:
假 设 有 字 符 串 s 0 , 先 经 过 复 制 得 到 2 s 0 , 再 向 2 s 0 中 插 入 一 个 字 符 x , 得 到 字 符 串 s 。 假设有字符串s_0,先经过复制得到2s_0,再向2s_0中插入一个字符x,得到字符串s。 假设有字符串s0,先经过复制得到2s0,再向2s0中插入一个字符x,得到字符串s。
现 在 给 定 s , 判 断 能 否 复 原 到 s 0 。 现在给定s,判断能否复原到s_0。 现在给定s,判断能否复原到s0。
若 能 , 输 出 s 0 ; 若 有 多 种 方 案 , 输 出 : “ N O T U N I Q U E ” ; 若 不 能 , 输 出 : “ N O T P O S S I B L E ” 。 若能,输出s_0;\\若有多种方案,输出:“NOT \ \ \ UNIQUE”;\\若不能,输出:“NOT \ \ \ POSSIBLE”。 若能,输出s0;若有多种方案,输出:“NOT UNIQUE”;若不能,输出:“NOT POSSIBLE”。
样例:
Sample Input:
S
a
m
p
l
e
I
n
p
u
t
1
:
7
A
B
X
C
A
B
C
S
a
m
p
l
e
I
n
p
u
t
2
:
6
A
B
C
D
E
F
S
a
m
p
l
e
I
n
p
u
t
3
:
9
A
B
A
B
A
B
A
B
A
\\ \ \\Sample\ \ Input1: \\7 \\ABXCABC \\ \ \\Sample \ \ Input2: \\6 \\ABCDEF \\ \ \\Sample \ \ Input3: \\9 \\ABABABABA
Sample Input1:7ABXCABC Sample Input2:6ABCDEF Sample Input3:9ABABABABA
Sample Output:
S a m p l e O u t p u t 1 : A B C S a m p l e O u t p u t 2 : N O T P O S S I B L E S a m p l e O u t p u t 3 : N O T U N I Q U E \\Sample \ \ Output1: \\ABC \\ \ \\Sample \ \ Output2: \\NOT\ \ POSSIBLE \\ \ \\ Sample \ \ Output3: \\NOT\ \ UNIQUE Sample Output1:ABC Sample Output2:NOT POSSIBLE Sample Output3:NOT UNIQUE
数据范围
s
的
长
度
N
∈
[
2
,
2000001
]
。
s的长度N∈[2,2000001]。
s的长度N∈[2,2000001]。
题解:
① 、 若 N 为 偶 数 , 必 然 无 法 复 原 。 ② 、 先 删 除 一 个 字 符 , 枚 举 删 除 的 位 置 , 再 判 断 中 点 两 侧 的 子 串 是 否 相 同 。 需 要 注 意 的 是 , 若 用 s t r i n g 类 函 数 , 结 果 会 R E , 所 以 只 能 考 虑 哈 希 来 做 。 ①、若N为偶数,必然无法复原。\\②、先删除一个字符,枚举删除的位置,再判断中点两侧的子串是否相同。\\ \qquad需要注意的是,若用string类函数,结果会RE,所以只能考虑哈希来做。 ①、若N为偶数,必然无法复原。②、先删除一个字符,枚举删除的位置,再判断中点两侧的子串是否相同。需要注意的是,若用string类函数,结果会RE,所以只能考虑哈希来做。
具体落实:
①
、
若
s
长
度
为
偶
数
,
直
接
输
出
。
②
、
预
处
理
整
个
s
的
哈
希
值
。
③
、
枚
举
删
除
的
位
置
,
重
点
在
于
求
删
除
后
,
计
算
中
点
两
侧
的
子
串
的
哈
希
值
s
1
、
s
2
。
设
s
的
长
度
为
n
,
则
分
别
分
成
两
种
情
况
:
(
1
)
、
删
除
的
位
置
i
<
=
⌊
n
2
⌋
,
也
就
是
左
侧
的
子
串
需
要
分
成
两
段
来
计
算
哈
希
值
。
左
侧
的
哈
希
值
=
区
间
[
1
,
i
−
1
]
的
哈
希
值
+
区
间
[
i
+
1
,
⌊
n
2
⌋
+
1
]
的
哈
希
值
。
抽
象
地
,
s
1
=
h
[
1
,
i
−
1
]
+
h
[
i
+
1
,
⌊
n
2
⌋
+
1
]
。
还
要
注
意
,
h
[
1
,
i
−
1
]
需
要
向
高
位
移
动
⌊
n
2
⌋
−
i
+
1
位
,
即
在
i
右
侧
的
字
符
的
数
量
。
①、若s长度为偶数,直接输出。\\②、预处理整个s的哈希值。\\③、枚举删除的位置,重点在于求删除后,计算中点两侧的子串的哈希值s_1、s_2。\\\qquad设s的长度为n,则分别分成两种情况:\\\ \\\qquad(1)、删除的位置i<=\lfloor\frac{n}{2}\rfloor,也就是左侧的子串需要分成两段来计算哈希值。\\\qquad 左侧的哈希值=区间[1,i-1]的哈希值+区间[i+1,\lfloor\frac{n}{2}\rfloor+1]的哈希值。\\\qquad抽象地,s1=h[1,i-1]+h[i+1,\lfloor\frac{n}{2}\rfloor+1]。\\\qquad还要注意,h[1,i-1]需要向高位移动\lfloor\frac{n}{2}\rfloor-i+1位,即在i右侧的字符的数量。
①、若s长度为偶数,直接输出。②、预处理整个s的哈希值。③、枚举删除的位置,重点在于求删除后,计算中点两侧的子串的哈希值s1、s2。设s的长度为n,则分别分成两种情况: (1)、删除的位置i<=⌊2n⌋,也就是左侧的子串需要分成两段来计算哈希值。左侧的哈希值=区间[1,i−1]的哈希值+区间[i+1,⌊2n⌋+1]的哈希值。抽象地,s1=h[1,i−1]+h[i+1,⌊2n⌋+1]。还要注意,h[1,i−1]需要向高位移动⌊2n⌋−i+1位,即在i右侧的字符的数量。
否
则
的
话
,
左
侧
哈
希
值
为
区
间
[
1
,
⌊
n
2
⌋
]
的
哈
希
值
,
即
s
1
=
h
[
1
,
⌊
n
2
⌋
]
。
(
2
)
、
删
除
位
置
i
<
=
⌊
n
2
⌋
+
1
,
这
时
右
侧
区
间
的
长
度
>
=
⌊
n
2
⌋
,
故
右
侧
子
串
的
哈
希
值
可
直
接
计
算
。
s
2
=
h
[
n
−
⌊
n
2
⌋
+
1
,
n
]
,
这
里
左
端
点
通
过
右
端
点
来
确
定
比
较
容
易
。
否
则
,
右
侧
子
串
的
哈
希
值
需
要
分
成
两
端
计
算
。
左
侧
子
串
哈
希
值
=
区
间
[
⌊
n
2
⌋
+
1
,
i
−
1
]
的
哈
希
值
+
区
间
[
i
+
1
,
n
]
的
哈
希
值
。
即
s
2
=
h
[
⌊
n
2
⌋
+
1
,
i
−
1
]
+
[
i
+
1
,
n
]
。
同
样
的
,
h
[
⌊
n
2
⌋
+
1
,
i
−
1
]
需
要
向
高
位
移
动
n
−
(
i
+
1
)
+
1
位
,
即
i
右
侧
的
字
符
的
数
量
。
\qquad否则的话,左侧哈希值为区间[1,\lfloor\frac{n}{2}\rfloor]的哈希值,即s_1=h[1,\lfloor\frac{n}{2}\rfloor]。\\ \ \\ \qquad(2)、删除位置i<=\lfloor\frac{n}{2}\rfloor+1,这时右侧区间的长度>=\lfloor\frac{n}{2}\rfloor,故右侧子串的哈希值可直接计算。\\\qquad s_2=h[n-\lfloor\frac{n}{2}\rfloor+1,n],这里左端点通过右端点来确定比较容易。\\\qquad否则,右侧子串的哈希值需要分成两端计算。\\\qquad左侧子串哈希值=区间[\lfloor\frac{n}{2}\rfloor+1,i-1]的哈希值+区间[i+1,n]的哈希值。\\\qquad即s2=h[\lfloor\frac{n}{2}\rfloor+1,i-1]+[i+1,n]。\\\qquad同样的,h[\lfloor\frac{n}{2}\rfloor+1,i-1]需要向高位移动n-(i+1)+1位,即i右侧的字符的数量。
否则的话,左侧哈希值为区间[1,⌊2n⌋]的哈希值,即s1=h[1,⌊2n⌋]。 (2)、删除位置i<=⌊2n⌋+1,这时右侧区间的长度>=⌊2n⌋,故右侧子串的哈希值可直接计算。s2=h[n−⌊2n⌋+1,n],这里左端点通过右端点来确定比较容易。否则,右侧子串的哈希值需要分成两端计算。左侧子串哈希值=区间[⌊2n⌋+1,i−1]的哈希值+区间[i+1,n]的哈希值。即s2=h[⌊2n⌋+1,i−1]+[i+1,n]。同样的,h[⌊2n⌋+1,i−1]需要向高位移动n−(i+1)+1位,即i右侧的字符的数量。
向
高
位
移
动
i
位
就
是
乘
基
数
b
a
s
e
的
i
次
方
,
即
b
a
s
e
i
。
向高位移动i位就是乘基数base的i次方,即base^{i}。
向高位移动i位就是乘基数base的i次方,即basei。
④ 、 若 两 侧 哈 希 值 相 等 , 需 要 记 录 第 一 次 哈 希 值 以 及 删 除 的 位 置 i 。 ( 一 开 始 以 为 只 要 符 合 条 件 的 位 置 找 到 2 个 , 就 判 断 方 案 不 唯 一 , 事 实 上 是 不 符 合 题 意 的 , 因 为 删 除 不 同 位 置 的 字 符 , 两 侧 的 哈 希 值 可 能 都 为 同 一 值 。 ) 因 此 需 要 记 录 哈 希 值 , 若 再 次 相 等 时 , 哈 希 值 与 第 一 次 的 哈 希 值 不 同 , 说 明 方 案 不 唯 一 。 ④、若两侧哈希值相等,需要记录第一次哈希值以及删除的位置i。\\\qquad(一开始以为只要符合条件的位置找到2个,就判断方案不唯一,事实上是不符合题意的,\\\qquad因为删除不同位置的字符,两侧的哈希值可能都为同一值。)因此需要记录哈希值,\\\qquad若再次相等时,哈希值与第一次的哈希值不同,说明方案不唯一。 ④、若两侧哈希值相等,需要记录第一次哈希值以及删除的位置i。(一开始以为只要符合条件的位置找到2个,就判断方案不唯一,事实上是不符合题意的,因为删除不同位置的字符,两侧的哈希值可能都为同一值。)因此需要记录哈希值,若再次相等时,哈希值与第一次的哈希值不同,说明方案不唯一。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#define ull unsigned long long
using namespace std;
const int base=131;
const int N=2e6+10;
int n,pos;
ull p[N],h[N],ans;
bool flag;
char s[N];
ull get(int l ,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
if(n%2==0) {puts("NOT POSSIBLE");return 0;}
p[0]=1;
for(int i=1;i<=n;i++) p[i]=p[i-1]*base;
for(int i=1;i<=n;i++) h[i]=h[i-1]*base+s[i]-'A';
for(int i=1;i<=n;i++)
{
ull s1,s2;
if(i<=n/2) s1=get(i+1,n/2+1)+h[i-1]*p[n/2-i+1];
else s1 = h[n/2];
if(i<=n/2+1) s2=get(n-n/2+1,n);
else s2=get(n/2+1,i-1)*p[n - i]+get(i+1,n);
if(s1==s2)
{
if(flag && ans != s1)
{
printf("NOT UNIQUE\n");
return 0;
}
flag=true,ans=s1,pos=i;
}
}
if(flag)
{
for(int i=1,j=0;j<n/2;i++)
if(i!=pos)
printf("%c",s[i]),j++;
printf("\n");
}
else puts("NOT POSSIBLE");
return 0;
}