Luogu4199 萬徑人蹤滅 FFT、Manacher
阿新 • • 發佈:2018-12-02
先不考慮”不是連續的一段“這一個約束條件。可以知道:第$i$位與第$j$位相同,可以對第$\frac{i+j}{2}$位置上產生$1$的貢獻(如果$i+j$為奇數表明它會對一條縫產生$1$的貢獻),而每一個位置上或縫上的滿足條件的字串的個數就是$2^\text{貢獻}-1$。把$\frac{1}{2}$忽略掉,也就是說:第$i$位與第$j$位相同時會在第$i+j$位產生$1$的貢獻。這個是經典的生成函式+$FFT$求解的問題。具體來說,將$a,b$兩個字母分開計算,以計算$a$的貢獻為例,如果第$i$位上為$a$,則兩個多項式的$x^i$項的係數為$1$,否則為$0$,然後將兩個多項式做卷積得到的結果的每一項的係數就是$a$字母對每一位做的貢獻,$b$同理。
然後我們考慮減掉連續的一段。連續的一段就是一段迴文串,使用$Manacher$求解即可。
#include<bits/stdc++.h> #define ld long double //This code is written by Itst using namespace std; inline int read(){ int a = 0; bool f = 0; char c = getchar(); while(c != EOF && !isdigit(c)){ if(c == '-') f= 1; c = getchar(); } while(c != EOF && isdigit(c)){ a = (a << 3) + (a << 1) + (c ^ '0'); c = getchar(); } return f ? -a : a; } const int MAXN = 280010 , MOD = 1e9 + 7; char s[MAXN >> 1] , news[MAXN]; struct comp{ ld x , y; comp(ld _x= 0 , ld _y = 0){ x = _x; y = _y; } comp operator +(comp a){ return comp(x + a.x , y + a.y); } comp operator -(comp a){ return comp(x - a.x , y - a.y); } comp operator *(comp a){ return comp(x * a.x - y * a.y , x * a.y + y * a.x); } }A[MAXN]; int need , dir[MAXN] , calc[MAXN] , manacher[MAXN]; const ld pi = acos(-1); inline int poww(long long a , int b){ int times = 1; while(b){ if(b & 1) times = times * a % MOD; a = a * a % MOD; b >>= 1; } return times; } inline void swap(comp& a , comp& b){ comp t = a; a = b; b = t; } inline void FFT(int type){ comp wn , w; for(int i = 1 ; i < need ; ++i) if(i < dir[i]) swap(A[i] , A[dir[i]]); for(int i = 1 ; i < need ; i <<= 1){ wn = comp(cos(pi / i) , type * sin(pi / i)); for(int j = 0 ; j < need ; j += i << 1){ w = comp(1 , 0); for(int k = 0 ; k < i ; ++k , w = w * wn){ comp x = A[j + k] , y = A[i + j + k] * w; A[j + k] = x + y; A[i + j + k] = x - y; } } } } int main(){ #ifndef ONLINE_JUDGE freopen("4199.in" , "r" , stdin); //freopen("4199.out" , "w" , stdout); #endif scanf("%s" , s); int l = strlen(s) , sum = 0; need = 1; while(need < l << 1) need <<= 1; for(int i = 1 ; i < need ; ++i) dir[i] = (dir[i >> 1] >> 1) | (i & 1 ? need >> 1 : 0); for(int i = 0 ; i < l ; ++i) if(s[i] == 'a') A[i].x = 1; FFT(1); for(int i = 0 ; i < need ; ++i) A[i] = A[i] * A[i]; FFT(-1); for(int i = 0 ; i < need ; ++i) calc[i] = A[i].x / need / 2 + 0.6; memset(&A , 0 , sizeof(A)); for(int i = 0 ; i < l ; ++i) if(s[i] == 'b') A[i].x = 1; FFT(1); for(int i = 0 ; i < need ; ++i) A[i] = A[i] * A[i]; FFT(-1); for(int i = 0 ; i < need ; ++i){ calc[i] += A[i].x / need / 2 + 0.6; sum = (sum + poww(2 , calc[i]) - 1) % MOD; } for(int i = 0 ; i < l ; ++i) news[(i << 1) + 1] = s[i]; int maxD = 0 , maxI = 0; for(int i = 1 ; i < l << 1 ; ++i){ if(maxD > i) manacher[i] = min(manacher[maxI * 2 - i] , maxD - i - 1); while(i - manacher[i] >= 0 && i + manacher[i] <= l << 1 && news[i - manacher[i]] == news[i + manacher[i]]) ++manacher[i]; sum = (sum - (manacher[i] >> 1) + MOD) % MOD; if(i + manacher[i] > maxD){ maxD = i + manacher[i]; maxI = i; } } cout << sum; return 0; }