前言:WA了无数次,记录下坑点(太菜了还是qwq)
思路:
1. 对字符串U进行字符串哈希的求解。
2. 枚举每个字符,判断当这个字符是被插入的那个字符时,剩余的串能否满足前(n - 1) / 2
个字符等于剩余字符。
3. 再求剔除一个字符后,新的字符串分成左右两半后各自的哈希值,具体情况如下:
len = n - 1 >> 1; // S串的长度
i > len:
左边串:h[len]
右边串:(h[i - 1] - h[len + 1 - 1] * p[i - len - 1]) * p[n - i] + (h[n] - h[i + 1 - 1] * p[n - i])
i <= len:
右边串:h[n] - h[n - len + 1 - 1] * p[len]
左边串:h[i - 1] * p[len + 1 - i - 1 + 1] + (h[len + 1] - h[i + 1 - 1] * p[len - i + 1])
坑点:
题目的“如果字符串S不唯一”这句话,表明了对于一个给定的U串,只有S在不同的情况下并且仍能组成U才算不唯一,例如像”AAA”,可以发现枚举三个位置后都可以满足构造方式,即S = 'A'
,我一开始没有注意这个点,就只是将左右串出现多次哈希值相同的时cnt ++
,这样判断是否唯一是错误的(在前面的例子里,就会使得cnt = 3
,得出不唯一的错误结论)。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL;
const int N = 2e6 + 10, P = 131;
int n;
char s[N];
ULL h[N], p[N];
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
cin >> n >> s + 1;
p[0] = 1;
for(int i = 1;i <= n;i ++ )
{
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + s[i];
}
int k = 0;
int len = n / 2; // 向下取整
ULL last = 0;
for(int i = 1;i <= n;i ++ )
{
ULL l, r;
if(i > len)
{
l = get(1, len);
r = get(len + 1, i - 1) * p[n - i] + get(i + 1, n);
}
else
{
r = get(n - len + 1, n);
l = get(1, i - 1) * p[len - i + 1] + get(i + 1, len + 1);
}
if(l == r)
{
if(!last) last = l;
else if(last != l)
{
puts("NOT UNIQUE");
return 0;
}
if(!k) k = i;
}
}
if(!last || n % 2 == 0)
{
cout << "NOT POSSIBLE" << endl;
return 0;
}
for(int i = 1, j = 0;j < len;i ++ )
if(i == k) continue;
else
{
cout << s[i];
j ++ ;
}
return 0;
}