bzoj3160 万径人踪灭
题目大意:给你一个ab序列,问不连续回文子序列的个数.
FFT加上一些计数原理即可A掉此题,主要需要注意的是两字符间的位置也需要运算.
对FFT,感觉就是一个双重循环,不过这个双重循环内部运算必须是乘法,而且复杂度不错.
无聊的话,每个FFT的题基本上都可以写成双重循环的结构.
顺便学一下mancher.
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<cmath> #include<algorithm> #include<queue> #include<set> #include<map> #include<iomanip> using namespace std; #define LL long long #define up(i,j,n) for(LL i=j;i<=n;i++) #define pii pair<LL,LL> #define db double #define eps 1e-4 #define FILE "dealing" LL read(){ LL x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();} return x*f; } const LL maxn=401000,inf=1000000000000000LL,limit=20000,mod=1000000007; bool cmin(LL& a,LL b){return a>b?a=b,true:false;} bool cmax(LL& a,LL b){return a<b?a=b,true:false;} namespace Mancher{ char ch[maxn]; LL p[maxn]; LL solve(char* s,LL n){ LL mx=0,id=0,m=0; ch[m++]='&';ch[m++]='#'; up(i,0,n-1){ ch[m++]=s[i]; ch[m++]='#'; } for(LL i=1;i<m;i++){ if(i<mx)p[i]=min(p[2*id-i],mx-i); else p[i]=1; while(ch[i+p[i]]==ch[i-p[i]])p[i]++; if(i+p[i]>mx){ mx=i+p[i]; id=i; } } LL ret=0; for(LL i=1;i<m;i++)ret=(ret+p[i]/2)%mod; return ret; } }; namespace FFT{ struct cp{ db x,y; cp(db x=0,db y=0):x(x),y(y){} cp operator+(const cp& b){return cp(x+b.x,y+b.y);} cp operator-(const cp& b){return cp(x-b.x,y-b.y);} cp operator*(const cp& b){return cp(x*b.x-y*b.y,x*b.y+y*b.x);} }w[maxn],A[maxn],B[maxn]; inline void swap(cp& a,cp& b){cp t(a);a=b;b=t;} LL R[maxn],H=1,L=1; db pi=(acos(-1.0)); void FFT(cp* a,LL f){ for(LL i=0;i<L;i++)if(i<R[i])swap(a[i],a[R[i]]); for(LL len=2;len<=L;len<<=1){ LL l=len>>1; cp wn(cos(pi/l),f*sin(pi/l)); for(LL i=1;i<l;i++)w[i]=w[i-1]*wn; for(LL st=0;st<L;st+=len){ for(LL k=0;k<l;k++) { cp x=a[st+k],y=w[k]*a[st+k+l]; a[st+k]=x+y,a[st+k+l]=x-y; } } } if(f==-1)up(i,0,L-1)a[i].x/=L; } void solve(LL* c,LL* d,LL n,LL m,LL* ch){ for(H=0,L=1;L<n+m-1;H++)L<<=1; up(i,0,L-1)A[i].x=c[i],A[i].y=0; up(i,0,L-1)B[i].x=d[i],B[i].y=0; w[0].x=1; up(i,0,L)R[i]=(R[i>>1]>>1)|((i&1)<<(H-1)); FFT(A,1);FFT(B,1); for(LL i=0;i<L;i++)A[i]=A[i]*B[i]; FFT(A,-1); for(LL i=0;i<L;i++)ch[i]=(LL)(A[i].x+0.5); } }; LL n; char s[maxn],ch[maxn]; LL a[maxn],b[maxn],c[maxn]; LL mul(LL a,LL b){LL ans=1;for(;b;a=a*a%mod,b>>=1)if(b&1)ans=ans*a%mod;return ans;} LL f[maxn]; int main(){ freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); scanf("%s",s); n=strlen(s); up(i,0,n-1)ch[i]=s[i]; LL y=Mancher::solve(ch,n); up(i,0,n-1)a[i]=s[i]=='a'; up(i,0,n-1)b[i]=s[i]=='b'; FFT::solve(a,a,n,n,c); for(int i=0;i<n<<1;i++)f[i]+=c[i]; FFT::solve(b,b,n,n,c); for(int i=0;i<n<<1;i++)f[i]+=c[i]; LL ans=0; for(int i=0;i<n<<1;i++) ans=(ans+mul(2,(f[i]+1)/2)+mod-1)%mod; ans=(ans%mod-y+mod)%mod; printf("%lld\n",ans); return 0; }