题解 P4199【万径人踪灭】
题意
给一个长度为 $n$ 的,字符集为 $2$ 的字符串 $s$,求满足以下三个条件的字符串 $t$ 的数量。
- $t\in\text{subsequences}(s)$;
- $t\notin\text{substrings}(s)$;
- $t$ 在 $s$ 中的位置、字符沿某对称中心对称。
其中 $n\le 10^5$。
思路
首先求出满足 $1,3$ 条件的 $t$ 的数量减去不满足 $2$ 条件的 $t$ 的数量即可,后者可以 $\text{Manacher}$ 或者 $\text{PAM}$ 解决,不是本题重点,故只讨论前者。
我们可以考虑转换思路,枚举对称中心计算答案之和。
令 $f_i$ 表示以 $i$ 为对称中心时对称的字母个数,则$$f_i=\sum_{j=1}^i[s_j=s_{2i-j}]$$ 容易得知,对于这 $f_i$ 对数中每对都可选或不选,但不能全部不选,所以 $i$ 处的的答案为 $2^{f_i}-1$。
当 $g_i=[s_i=c]$ 时,$s_i=s_j=c$ 当且仅当 $g_i=g_j=1$,即 $g_i\times g_j=1$。
那么枚举 $c$,构造多项式 $F$,其中 $F_i=[s_i=c]$,那么可以直接计算 $F^2$ 计入答案即可。实现时需要注意判断对称中心是在原字符串上还是插入的字符上。
时间复杂度 $O(n\log n)$。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
//here was something
}
const int N=4e5+10,mod=1e9+7;
char str[N],input[N];
int p[N],ans[N],n,sum;
inline void getc(char *a,char *b,int n){
int len=0;
b[len++]='~';
b[len++]='|';
for(int i=1;i<=n;i++){
b[len++]=a[i];
b[len++]='|';
}
b[n*2+2]=0;
len--;
}
inline int qpow(int x,int y){
int res=1;
while(y){
if(y&1) res=1ll*res*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return res;
}
#define ld double
const ld pi=acos(-1);
struct comp{
ld x,y;
comp(ld a=0,ld b=0){x=a,y=b;}
comp neg(){ return comp(x,-y); }
friend comp operator+(const comp &a,const comp &b){ return comp(a.x+b.x,a.y+b.y); }
friend comp operator-(const comp &a,const comp &b){ return comp(a.x-b.x,a.y-b.y); }
friend comp operator*(const comp &a,const comp &b){ return comp(a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y); }
};
int rev[N],lim;
inline int add(int x,int y){ return x+y>=mod?x+y-mod:x+y; }
inline int dec(int x,int y){ return x>=y?x-y:x-y+mod; }
inline void init(int n,int mode=1){
if(mode){
int l=0;
for(lim=1;lim<=n;lim<<=1)l++;
for(int i=0;i<lim;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1);
}
}else{
for(lim=1;lim<=n;lim<<=1);
}
}
inline void FFT(comp *a,int lim,int tpe){
for(int i=0;i<lim;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int i=1;i<lim;i<<=1){
comp wn(cos(pi/i),tpe*sin(pi/i));
for(int j=0;j<lim;j+=(i<<1)){
comp w(1);
for(int k=0;k<i;k++,w=w*wn){
comp t=a[i+j+k]*w;
a[i+j+k]=a[j+k]-t;
a[j+k]=a[j+k]+t;
}
}
}
if(tpe==-1){
double p=1./lim;
for(int i=0;i<lim;i++)
a[i].x*=p,a[i].y*=p;
}
}
comp A[N];
int main(){
n=readstr(input);
getc(input,str,n);
for(int i=1,r=0,mid=0;i<=n*2+1;i++){
if(i<r)
p[i]=min(p[(mid<<1)-i],r-i);
while(str[i-p[i]]==str[i+p[i]])
p[i]++;
if(i+p[i]>r)
r=i+p[i],mid=i;
}
init(n<<1);
for(int i=1;i<=n;i++)
A[i].x=input[i]=='a';
FFT(A,lim,1);
for(int i=0;i<lim;i++)
A[i]=A[i]*A[i];
FFT(A,lim,-1);
for(int i=1;i<=n*2+1;i++)
ans[i]+=(int(A[i].x+0.5)-(i%2==0));
for(int i=0;i<lim;i++)
A[i].x=A[i].y=0;
for(int i=1;i<=n;i++)
A[i].x=input[i]=='b';
FFT(A,lim,1);
for(int i=0;i<lim;i++)
A[i]=A[i]*A[i];
FFT(A,lim,-1);
for(int i=1;i<=n*2+1;i++)
ans[i]+=(int(A[i].x+0.5)-(i%2==0));
for(int i=1;i<=n*2+1;i++)
ans[i]=((ans[i]+(i%2==0))>>1)+(i%2==0);
for(int i=1;i<=n*2+1;i++)
ans[i]=qpow(2,ans[i])-1;
for(int i=1;i<=n*2+1;i++)
ans[i]-=p[i]>>1;
for(int i=1;i<=n*2+1;i++)
sum=(sum+ans[i])%mod;
printf("%d\n",sum);
return 0;
}
再见 qwq~

浙公网安备 33010602011771号