1. 程式人生 > >【迴文樹 && 求本質不同迴文串的和】ACM-ICPC 2018 南京賽區網路預賽 I. Skr

【迴文樹 && 求本質不同迴文串的和】ACM-ICPC 2018 南京賽區網路預賽 I. Skr

Step1 Problem:

給你一個字串 s,求本質不同的迴文字串的加和 mod 1e9+7。
例:s = “1111”, ans = 1111 + 111 + 11 + 1.
資料範圍:
1 <= len <= 2e6. 1 <= s[i] <= 9.

Step2 Ideas:

前置技能:4348 = ((4*10 + 3)*10+4)*10 + 8,這樣我們就可以隨便取 mod 了。
分別從 0,1 開始 bfs. 偶數奇數分開算
0 偶數:
當前迴文串為空 其結果為 ans = 0,下次變成 11 = 1*10 + ans*10 + 1.
當前迴文串為 11 其結果為 ans = 11,下次變成 1111 = 1*1000 + ans*10 + 1.
1 奇數:
當前迴文串為空 其結果為 ans = 0,下次變成 5 = 5.//預處理,即可
當前迴文串為 5 其結果為 ans = 5,下次變成 555 = 1*100 + ans*10 + 5.
當前迴文串為 555 其結果為 ans = 555+5 = 560,下次變成 55555 = 1*10000 + ans*10 + 5.

Step3 Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e6+5;
const int MOD = 1e9+7;
struct node
{
    int len, cnt, pos;
    int next[10], fail;//只有26個小寫字母
}a[N];
int top, last;
char s[N];
void Init_Tr()
{
    top = 1, last = 0;
    a[0].len = 0, a[1].len = -1
; a[0].fail = 1; } int i;//減少傳參可以優化很大的時間複雜度 int get_id(int now) { while(s[i] != s[i-a[now].len-1]) now = a[now].fail; return now; } void Insert() { int len = strlen(s+1); for(i = 1; i <= len; i++) { int t = s[i]-'0'; int id = get_id(last); if(!a[id].next[t]) { a[++top].len = a[id].len + 2
; a[top].pos = i; a[top].fail = a[get_id(a[id].fail)].next[t]; a[id].next[t] = top; } last = a[id].next[t]; a[last].cnt++; } } struct Q { int pos; ll now, z; }; ll solve() { ll ans = 0; queue<Q> q; for(int i = 0; i < 10; i++) {//奇數預處理長度為 1 的迴文串 if(a[1].next[i]) { q.push((Q){a[1].next[i], i, 100}); } } while(!q.empty()) { Q u = q.front(); q.pop(); ans += u.now; ans %= MOD; for(int i = 0; i < 10; i++) { if(a[u.pos].next[i]) { ll now = i*u.z + u.now*10 + i; now %= MOD; ll z = u.z*100; z %= MOD; q.push((Q){a[u.pos].next[i], now, z}); } } } q.push((Q){0, 0, 10}); while(!q.empty()) { Q u = q.front(); q.pop(); ans += u.now; ans %= MOD; for(int i = 0; i < 10; i++) { if(a[u.pos].next[i]) { ll now = i*u.z + u.now*10 + i; now %= MOD; ll z = u.z*100; z %= MOD; q.push((Q){a[u.pos].next[i], now, z}); } } } return ans; } int main() { scanf("%s", s+1); //1111111111111 Init_Tr(); Insert(); printf("%lld\n", solve()); return 0; }