Luogu P4199 万径人踪灭
Posted jackpei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P4199 万径人踪灭相关的知识,希望对你有一定的参考价值。
我们把所有相同的字符对的贡献求出来,减去回文子串的个数,就是最后的答案。
求每个回文中心的相同字母对个数 (f[i]) ,我们可以用卷积去求。贡献是 (2^{f[i]/2+[i\%2==0]-1}) ,([i\%2==0]) 表示位置在 (frac{i}{2}) 的字符仅会被记一次,(/2) 时会除掉,所以我们要加上。
回文子串个数可以用 (PAM) 求。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=400010,M=1000000007;
const double PI=acos(-1.0);
int n,p[N],K,len,f[N],ans;
char s[N];
struct ci {
double x,y;
inline ci operator + (const ci& that) const
{return (ci){x+that.x,y+that.y};}
inline ci operator - (const ci& that) const
{return (ci){x-that.x,y-that.y};}
inline ci operator * (const ci& that) const
{return (ci){x*that.x-y*that.y,x*that.y+y*that.x};}
}a[N];
inline void fft(ci* a,int op) {
for(R i=0;i<K;++i) if(i<p[i]) swap(a[i],a[p[i]]);
for(R l=1;l<K;l<<=1) {
register ci w1=(ci){cos(PI/l),op*sin(PI/l)},wn,x,y;
for(R len=l<<1,i=0;i<K;i+=len) {
wn=(ci){1,0};
for(R j=0;j<l;++j,wn=wn*w1)
x=a[i+j],y=wn*a[i+j+l],a[i+j]=x+y,a[i+j+l]=x-y;
}
}
}
struct PAM {
int lst,tot,fa[N],len[N],c[N][26],sz[N]; ll ans;
inline void init() {len[fa[0]=tot=1]=-1;}
inline int jmp(int p,int i)
{while(s[i-len[p]-1]!=s[i]) p=fa[p]; return p;}
inline void ext(int ch,int i) {
R p=jmp(lst,i); if(!c[p][ch]) {
R np=++tot; len[np]=len[p]+2;
R t=jmp(fa[p],i);
fa[np]=c[t][ch],c[p][ch]=np;
} ++sz[lst=c[p][ch]];
}
inline void cal() {
for(R i=tot;i>=2;--i)
sz[fa[i]]+=sz[i],ans+=sz[i];
}
}p1;
inline int qpow(int a,int b) { R ret=1;
for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret;
}
inline void main() {
scanf("%s",s+1),n=strlen(s+1),p1.init();
for(R i=1;i<=n;++i) p1.ext(s[i]-'a',i);
K=1; while(K<=2*n) K<<=1,++len;
for(R i=0;i<K;++i) p[i]=(p[i>>1]>>1)|((i&1)<<(len-1));
for(R i=1;i<=n;++i) a[i].x=s[i]=='a',a[i].y=0;
fft(a,1); for(R i=0;i<K;++i) a[i]=a[i]*a[i];
fft(a,-1); for(R i=0;i<K;++i) f[i]=(f[i]+(int)(a[i].x/K+0.5))%M;
memset(a,0,sizeof a);
for(R i=1;i<=n;++i) a[i].x=s[i]=='b',a[i].y=0;
fft(a,1); for(R i=0;i<K;++i) a[i]=a[i]*a[i];
fft(a,-1); for(R i=0;i<K;++i) f[i]=(f[i]+(int)(a[i].x/K+0.5))%M;
p1.cal(); ans=-p1.ans%M;
for(R i=1;i<=2*n;++i) ans=(ans+qpow(2,f[i]/2+((i&1)^1))-1)%M;
printf("%d
",(ans+M)%M);
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.16
以上是关于Luogu P4199 万径人踪灭的主要内容,如果未能解决你的问题,请参考以下文章