版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Cymbals/article/details/82707686
题目:https://nanti.jisuanke.com/t/30998
计蒜客开了禁止复制,我挂了破解网页限制的脚本能复制但是不太好看,就不贴题目了。
题目大意是给出一个数字串,求其本质不同的回文子串的和。
一开始没看到“本质不同”,上来就想跑马拉车 + Sam,重新读题后扑街。
后来知道是回文树的题,学完了回文树才补。
在回文树建立的过程中自带去重,所以只需要跑一遍记录答案就好了。
奇根下直接连接的节点所代表的的都是单个字符的回文串,其他都是在两边加上同一个字符,用这个规律去生成数字求和就好了。
ac代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2000005;
const int mod = 1000000007;
char s[maxn];
ll modPow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) {
ans = (ans * a) % mod;
}
b >>= 1;
a = (a * a) % mod;
}
return ans;
}
struct Pam {
int next[maxn][9];
int fail[maxn];
int len[maxn];
// 记录数字
ll num[maxn];
ll ans;
int S[maxn];
int last, n, p;
int newNode(int l) {
memset(next[p], 0, sizeof(next[p]));
len[p] = l;
return p++;
}
void init() {
n = last = p = 0;
newNode(0);
newNode(-1);
S[n] = -1;
fail[0] = 1;
}
int getFail(int x) {
while(S[n - len[x] - 1] != S[n]) {
x = fail[x];
}
return x;
}
void add(int c) {
S[++n] = c;
int cur = getFail(last);
if(!next[cur][c]) {
int now = newNode(len[cur] + 2);
fail[now] = next[getFail(fail[cur])][c];
next[cur][c] = now;
// len[cur] = -1时,是单个字符组成的回文串,特判
if(len[cur] == -1) {
num[now] = c;
} else {
num[now] = (((num[cur] * 10) % mod + c) % mod + (c * modPow(10, len[now] - 1)) % mod) % mod;
}
ans = (ans + num[now]) % mod;
}
last = next[cur][c];
}
void solve() {
init();
for(int i = 0, len = strlen(s); i < len; i++) {
add(s[i] - '0');
}
printf("%lld\n", ans);
}
} pam;
int main() {
scanf("%s", s);
pam.solve();
return 0;
}