E Falfa with Substring
E 题题意:给定长度 ,问长度为 的纯小写字母串中出现 次 bit
的字符串个数,需要对 输出答案。。
解法:对于恰好类问题,通常将其转化为至少或至多。
若至少出现 次 bit
,因为这个字符串不会重叠出现,因而可以将其绑定成一个特殊字符,等效于在 个位置中选择 个位置填放 bit
,剩余位置任选。因而至少 次出现的方案数为 。这部分可以 的求出。
接下来考虑容斥:恰有 个出现的需要从 处转移。对于某一个 ,其转移方案应当是从恰好 个 bit
的方案中选择出 k
个出来作为最终恰好的部分,剩余的都要扔掉。因而恰好 个的方案数为 。
显然该式子还是没办法快速计算。注意到 ,因而利用二项式反演得到 。将其进行整理:
注意到 为一定值,因而构成差卷积形式。使用 NTT 可以加速这一过程,总复杂度 。
使用队友通过的代码:
#include<bits/stdc++.h>
#define IL inline
#define LL long long
using namespace std;
const int N=4e6+3,M=1e7+3,p=998244353,G=3,Gi=332748118;
int n,m,S,a[N],b[N],c[N],r[N],val[N],fac[M],inv[M],cf[N],ans;
IL int in(){
char c;int f=1;
while((c=getchar())<'0'||c>'9')
if(c=='-') f=-1;
int x=c-'0';
while((c=getchar())>='0'&&c<='9')
x=x*10+c-'0';
return x*f;
}
IL int mod(int x){return x>=p?x-p:x;}
IL int ksm(int a,int b){
int c=1;
while(b){
if(b&1) c=1ll*c*a%p;
a=1ll*a*a%p,b>>=1;
}
return c;
}
IL void calc(int lim){
for(int i=0;i<lim;++i)
r[i]=(r[i>>1]>>1)|((i&1)*(lim>>1));
}
IL void init(int n){
fac[0]=1;for(int i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%p;
inv[n]=ksm(fac[n],p-2);
for(int i=n;i;--i) inv[i-1]=1ll*inv[i]*i%p;
cf[0]=1;for(int i=1;i<=n;++i) cf[i]=1ll*cf[i-1]*26%p;
}
IL void NTT(int *a,int lim,int op){
calc(lim);
for(int i=0;i<lim;++i)
if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=ksm(~op?G:Gi,(p-1)/(i<<1));
for(int j=0;j<lim;j+=i<<1){
int w=1;
for(int k=0;k<i;++k,w=1ll*w*wn%p){
int x=a[j+k],y=1ll*w*a[j+i+k]%p;
a[j+k]=mod(x+y),a[j+i+k]=mod(x-y+p);
}
}
}
if(op==-1){
int inv=ksm(lim,p-2);
for(int i=0;i<lim;++i) a[i]=1ll*a[i]*inv%p;
}
}
IL void mul(int *a,int *b,int *c,int n,int m){
int lim=1,_a[N],_b[N];
while(lim<n+m-1) lim<<=1;
memcpy(_a,a,4*n),memcpy(_b,b,4*m),
memset(_a+n,0,4*(lim-n)),memset(_b+m,0,4*(lim-m));
NTT(_a,lim,1),NTT(_b,lim,1);
for(int i=0;i<lim;++i) c[i]=1ll*_a[i]*_b[i]%p;
NTT(c,lim,-1);
}
IL int C(int n,int m){return 1ll*fac[n]*inv[m]%p*inv[n-m]%p;}
int main()
{
n=in(),init(n);
int Max=n/3;
for(int i=0;i<=Max;++i)
a[i]=1ll*C(n-2*i,i)*cf[n-3*i]%p*fac[i]%p;
for(int i=0;i<=Max;++i)
if(i&1) b[i]=mod(p-inv[i]);
else b[i]=inv[i];
reverse(a,a+Max+1);
mul(a,b,a,Max+1,Max+1);
reverse(a,a+Max+1);
for(int i=0;i<=Max;++i) a[i]=1ll*a[i]*inv[i]%p;
for(int i=0;i<=Max;++i) printf("%d ",a[i]);
for(int i=Max+1;i<=n;++i) printf("0 ");
return 0;
}