BZOJ3160 萬徑人蹤滅
阿新 • • 發佈:2018-04-01
www. 最長回文 部分 lin 就是 etc printf -o 題解
怎麽求這個東西呢?
設\(s[x],s[y]\)關於\(s[e]\)對稱,那麽它們的下標滿足\(x + y = 2e\)。
長得像一個卷積啊......
所以說,對於一個字符\(c\),若\(s[i]=c\),那麽多項式\(f[i]=1\),否則為\(0\)。
兩個這樣的多項式卷積\(f\)卷起來就可以得到所有的\(t_i\)了。
然後考慮刪掉不合法的情況(即只有連續一段的情況)。
這個簡直弱智啊,\(manacher\)一下求出最長回文半徑\(P\)不就行了嗎?
註意回文串中虛擬字符#的影響,在對應部分對應的除2即可。
BZOJ3160 萬徑人蹤滅
題目大意
給定一個字符串\(S\),\(|S|=n\),字符集為\(\{a,b\}\)
現在要求滿足下面條件的子序列個數:
- 滿足其存在一個對稱中心(是回文子序列)。
- 至少分為3段,即不能只有連續一段。
我怕我的題意歸納出鍋所以放一下題目網址:web
問滿足條件的子序列個數。數據範圍:\(n \leq 10^5\)
題解
首先先\(manacher\)那一套轉換一下字符串(間隙間加#)。
假設沒有不能連續的限制。
如果我們知道以某個點\(i\)為對稱中心的左右兩邊對稱點對有\(t_i\)個。
那麽符合條件的子序列個數就是\(2^{t_i} - 1\)個(減去空串)。
設\(s[x],s[y]\)關於\(s[e]\)對稱,那麽它們的下標滿足\(x + y = 2e\)。
長得像一個卷積啊......
所以說,對於一個字符\(c\),若\(s[i]=c\),那麽多項式\(f[i]=1\),否則為\(0\)。
兩個這樣的多項式卷積\(f\)卷起來就可以得到所有的\(t_i\)了。
然後考慮刪掉不合法的情況(即只有連續一段的情況)。
這個簡直弱智啊,\(manacher\)一下求出最長回文半徑\(P\)不就行了嗎?
註意回文串中虛擬字符#的影響,在對應部分對應的除2即可。
實現代碼
我發現我還是記得打\(manacher\)的.....(O-O)。
#include<bits/stdc++.h> #define RG register #define IL inline #define _ 800005 #define ll long long #define mod 1000000007 using namespace std; IL int gi(){ RG int data = 0 , m = 1; RG char ch = 0; while(ch != '-' && (ch<'0' || ch > '9')) ch = getchar(); if(ch == '-'){m = 0; ch = getchar();} while(ch>='0' && ch<='9'){data = (data<<1) + (data<<3) + ch - '0' ; ch = getchar();} return (m) ? data : -data ; } const double PI = acos(-1) ; int R[_],P[_],mxpos,lr,ps,len,lg,nn,mm,db[_]; ll ans,ret[_]; char ycb[_],s[_] ; struct Complex{ double r , i ; IL Complex(){i = 0.0; r = 0.0; } IL Complex(double a,double b){r = a; i = b ; } IL Complex operator + (Complex A){ return Complex(r+A.r,i+A.i) ; } IL Complex operator - (Complex A){ return Complex(r-A.r,i-A.i) ; } IL Complex operator * (Complex A){ return Complex(A.r*r - i*A.i , A.r*i + A.i*r) ; } }f1[_],f2[_],X,Y; void FFT(Complex *F,int opt){ for(RG int i = 0; i < nn; i ++) if(i < R[i]) swap(F[i] , F[R[i]]) ; for(RG int i = 1; i < nn; i <<= 1){ Complex W(cos(PI/i) , opt*sin(PI/i)) ; for(RG int j = 0,e = (i<<1) ; j < nn; j += e){ Complex w(1,0) ; for(RG int k = 0; k < i; k ++,w = w*W){ X = F[j+k] ; Y = w * F[j+k+i] ; F[j+k] = X + Y ; F[j+k+i] = X - Y ; } } }if(opt==-1)for(RG int i = 0; i < nn; i ++) F[i].r = F[i].r / nn ; } IL void solve(char ch){ mm = 2*lg ; lr = 0; for(nn = 1; nn <= mm; nn<<=1) ++ lr ; lr --; for(RG int i = 0; i < nn; i ++) R[i] = (R[i>>1]>>1) | ((i&1) << lr) ; for(RG int i = 0; i <= nn; i ++) f1[i].r = f1[i].i = f2[i].r = f2[i].i = 0 ; for(RG int i = 0; i <= lg; i ++) if(s[i] == ch)f1[i].r = f2[i].r = 1; else f1[i].r = f2[i].r = 0; FFT(f1 , 1) ; FFT(f2 , 1) ; for(RG int i = 0; i <= nn; i ++) f1[i] = f1[i] * f2[i] ; FFT(f1 , -1) ; for(RG int i = 0; i <= lg; i ++) ret[i] = (ret[i] + ((long long)(f1[i<<1].r+0.5)+1)/2 ) % mod ; return ; } IL void manacher(){ P[1] = 1 ; mxpos = 2; ps = 1; for(RG int i = 2; i <= lg; i ++){ P[i] = (mxpos > i) ? min(mxpos - i , P[(ps<<1) - i]) : 0 ; while(i-P[i]-1>=0 && i+P[i]+1<= lg && s[i-P[i]-1] == s[i+P[i]+1]) ++ P[i] ; if(i+P[i] >= mxpos) mxpos = i+P[i] , ps = i ; }return ; } int main(){ scanf("%s",ycb) ; len = strlen(ycb) ; for(RG int i = 0; i <= len; i ++) s[i<<1] = '#' , s[i<<1|1] = ycb[i] ; lg = (len << 1) ; solve('a') ; solve('b') ; db[0] = 1; for(RG int i = 1; i <= lg; i ++) db[i] = 1ll * db[i-1] * 2 % mod ; for(RG int i = 1; i <= lg; i ++) ans = (ans + db[ret[i]] - 1) % mod ;; manacher(); for(RG int i = 1; i <= lg; i ++) ans = ((ans - (P[i]+1)/2) % mod + mod) % mod ; printf("%lld\n" , ans) ; return 0; }
BZOJ3160 萬徑人蹤滅