Luogu P4199 万径人踪灭
分析
条件2可以用容斥,Manacher
接下来只需求对于每个对称轴\(i\),有多少种点对选取方式满足关于\(i\)对称
不妨设\(f[i]\)表示以\(\frac{i}{2}\)为对称轴的对称点对数
\[ f[i]=\sum_{j+k=i}[s[j]==s[k]]
\]
像极了FFT,考虑FFT
又只有两个字母仿佛在暗示我们什么
可以设\(b[i]\)表示\(s[i]=='a'\),\(b'[i]\)表示\(s[i]=='b'\)
\[ f[i]=\sum_{j+k=i} b[j]*b[k]+b'[j]*b'[k]
\]
FFT优化
PS:注意FFT的精度问题
#include<bits/stdc++.h>
#define ll long long
#define db double
const int p=1e9+7;
double Pi=acos(-1);
using namespace std;
inline int mo(int x) {
return x>=p?x-p:x;
}
inline int ksm(ll a,int b) {
ll ret=1;
while(b) {
if(b&1) ret=ret*a%p;
a=a*a%p,b>>=1;
}
return ret;
}
const int N=4e5+5;
int ans,rev[N],L,n,m,len,R[N],f[N];
char s[N],a[N];
struct cp {double a,b; }b[N];
cp operator +(cp x,cp y) {
return (cp){x.a+y.a,x.b+y.b};
}
cp operator -(cp x,cp y) {
return (cp){x.a-y.a,x.b-y.b};
}
cp operator *(cp x,cp y) {
return (cp){x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a};
}
void fft(cp *a,int op) {
for(int i=0;i<len;i++) {
if(i>rev[i]) swap(a[i],a[rev[i]]);
}
for(int i=1;i<len;i<<=1) {
cp Wn=(cp){cos(Pi/i),sin(Pi/i)*op};
for(int j=0;j<len;j+=(i<<1)) {
cp w=(cp){1,0};
for(int k=j;k<j+i;k++) {
cp t=w*a[k+i];
a[k+i]=a[k]-t;
a[k]=a[k]+t;
w=w*Wn;
}
}
}
}
int main() {
scanf("%s",s+1),n=strlen(s+1);
L=0; len=1;
while(len<n+n-1) len<<=1,L++;
for(int i=1;i<=len;i++) {
rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
}
for(int i=0;i<n;i++) {
b[i].a=(s[i+1]=='a');
}
fft(b,1);
for(int i=0;i<len;i++) b[i]=b[i]*b[i];
fft(b,-1);
for(int i=0;i<len;i++) {
f[i]=(int)((b[i].a+0.5)/len);
}
for(int i=0;i<len;i++) {
b[i]=(cp){(db)(s[i+1]=='b'),0};
}
fft(b,1);
for(int i=0;i<len;i++) b[i]=b[i]*b[i];
fft(b,-1);
for(int i=0;i<len;i++) {
f[i]+=(int)((b[i].a+0.5)/len);
ans=mo(ans+ksm(2,f[i]+1>>1)-1);
}
a[0]='*',a[m=1]='|';
for(int i=1;i<=n;i++) {
a[++m]=s[i],a[++m]='|';
}
for(int i=1,r=0,mid=0;i<=m;i++){
if(i<=r) R[i]=min(R[(mid<<1)-i],r-i+1);
while(a[i+R[i]]==a[i-R[i]]) R[i]++;
if(i+R[i]>r) {
mid=i,r=i+R[i]-1;
}
ans=mo(ans-(R[i]>>1)+p);
}
printf("%d\n",ans);
return 0;
}

FFt,Manacher
浙公网安备 33010602011771号