P3449 [POI2006]PAL-Palindromes
Upd on 2022.9.3:换成更自然的推导方式。
*P3449 [POI2006]PAL-Palindromes
好题。
若
具体实现方法为枚举每个
实际上本题还有更巧妙的做法。
我们观察
进一步地,我们发现若 回文串
因为
-
因为
c 和c ^ R 均为s 的前缀,所以c 回文。 -
因为
bbb\cdots bc = c ^ Rb\cdots bbb ,所以bbb\cdots b 为a 的 border,因此|c| 为a 的周期。
综合上述两点,可知
不断应用上述结论,可知
若长度为
n 的 回文串s 存在 回文 周期p ,则s 存在长为\gcd(n, p) 的 回文整周期。
结合辗转相减法和上述结论易证。
又因为
综上,KMP 求出每个字符串的
每个本质不同的字符串对答案的贡献为
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
inline int read() {
int x = 0;
char s = getchar();
while(!isdigit(s)) s = getchar();
while(isdigit(s)) x = x * 10 + s - '0', s = getchar();
return x;
}
inline void print(int x) {
if(x < 0) return putchar('-'), print(-x);
if(x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
bool Mbe;
constexpr int N = 2e6 + 5;
int n, nxt[N];
char str[N];
string s[N];
bool Med;
int main() {
fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
#ifdef ALEX_WEI
FILE* IN = freopen("1.in", "r", stdin);
FILE* OUT = freopen("1.out", "w", stdout);
#endif
ios::sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; i++) {
int m;
cin >> m >> str + 1;
for(int j = 2, p = 0; j <= m; j++) {
while(p && str[p + 1] != str[j]) p = nxt[p];
nxt[j] = p += str[p + 1] == str[j];
}
if(m % (m - nxt[m]) == 0)
for(int j = 1; j <= m - nxt[m]; j++)
s[i] += str[j];
else
for(int j = 1; j <= m; j++)
s[i] += str[j];
}
sort(s + 1, s + n + 1);
ll ans = 0;
for(int i = 1; i <= n; i++) {
int r = i;
while(r < n && s[r + 1] == s[i]) r++;
ans += 1ll * (r - i + 1) * (r - i + 1);
i = r;
}
cout << ans << "\n";
cerr << TIME << " ms\n";
return 0;
}
/*
2022/9/3
author: Alex_Wei
start coding at 6:58
finish debugging at 7:05
*/