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

原文地址:https://www.cnblogs.com/Jackpei/p/12203188.html