题目
描述
有一个纸片,纸片上有(n)个格子,初始时没有颜色;
某个游戏的内容是进行(m)次染色,使得染完后(n)个格子一定有颜色;
每次可以选择一个区间([l,r](l le r))去染(不能不染),颜色可以覆盖;
问最后染出的序列有多少种;
范围
(n,m le 10^6) ;
题解
-
由于可以覆盖这个条件处理起来比较麻烦;
-
考虑每次是插入一段颜色;
-
[egin{cases} &f_{i,j} = f_{i-1,j} + sum_{k=0}^{j-1} f_{i-1,k}(k+1) &(i lt m)\ &f_{i,j} = sum_{k=1}^{j-1} f_{i-1,k}(k+1) &(i = m) \ end{cases} ]
-
插播一个我自己的十分没用的想法:
-
只考虑管第一个转移,设 $ F_{i} $ 为 $ f_{i,j} $ 的 $ OGF $ 对比 $ f_{i,j}和f_{i,j-1} $ ,有:
-
[F_{i} = F_{i-1} + xF_i + x^2(F_{i-1})' ; \ F_{i} = frac{(x^2F_{i-1})'-F_{i-1}}{1-x} ;\ ]
-
然后就没有然后了,。。。。。,TAT;
-
-
说正解:
-
方程中存在两类贡献,一种是(f_{i,j} imes (j+1)),一种是(f_{i,j} imes 1);
-
同时要求最后一次转移一定是第二种;
-
枚举第一种转移的次数(k),求得贡献和后乘以((^{m-1}_{k-1})) ,
-
考虑每次更新之后的形成的第一种转移次数的序列:(0 lt a_1 lt a_2 lt ,cdots, lt a_k = n) ;
-
对于一种转移序列的贡献就是:((a_1+1)cdots(a_{k-1}+1)) ;
-
这其实是([x^{n-k}]Pi_{i=1}^{n-1}(x+i+1)) ;
-
所以答案是:(sum_{k=1}^{m} (^{m-1}_{k-1})[x^{n-k}]Pi_{i=1}^{n-1}(x+i+1));
-
类似https://www.cnblogs.com/Paul-Guderian/p/10519990.html倍增可以(nlogn) ;
#include<bits/stdc++.h> #define ll long long #define mod 998244353 #define il inline using namespace std; const int N=4000010; int n,m,fac[N],inv[N],len,L,rev[N],f[N],g[N],a[N],b[N]; il int pw(int x,int y){ int re=1; if(y<0)y+=mod-1; while(y){ if(y&1)re=(ll)re*x%mod; y>>=1;x=(ll)x*x%mod; } return re; } il void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;} const int G=3; il void ntt(int*A,int F){ 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){ int wn=pw(G,F*(mod-1)/(i<<1)); for(int j=0;j<len;j+=i<<1){ int w=1; for(int k=0;k<i;++k,w=(ll)w*wn%mod){ int x=A[j+k],y=(ll)w*A[j+k+i]%mod; A[j+k]=(x+y)%mod,A[j+k+i]=(x-y+mod)%mod; } } } if(!~F){ int iv=pw(len,mod-2); for(int i=0;i<len;++i)A[i]=(ll)A[i]*iv%mod; } } void solve(int n){ if(n==1){f[0]=2;f[1]=1;return;} if(n&1){ solve(n-1); for(int i=n-1;~i;--i)inc(f[i+1],f[i]),f[i]=(ll)(n+1)*f[i]%mod; return ; } solve(n>>=1); for(len=1,L=0;len<(n+1)<<1;L++,len<<=1); for(int i=0;i<=len;++i){ rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); a[i]=b[i]=g[i]=0; } for(int i=0,pwn=1;i<=n;++i,pwn=(ll)pwn*n%mod){ a[i]=(ll)f[n-i]*fac[n-i]%mod; b[i]=(ll)pwn*inv[i]%mod; } ntt(a,1);ntt(b,1); for(int i=0;i<len;++i)a[i]=(ll)a[i]*b[i]%mod; ntt(a,-1); for(int i=0;i<=n;++i)g[i]=(ll)inv[i]*a[n-i]%mod; ntt(f,1);ntt(g,1); for(int i=0;i<len;++i)f[i]=(ll)f[i]*g[i]%mod; ntt(f,-1); } int C(int x,int y){return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;} int main(){ freopen("color.in","r",stdin); freopen("color.out","w",stdout); scanf("%d%d",&n,&m); for(int i=fac[0]=inv[0]=1;i<=m||i<=n;++i){ fac[i]=(ll)fac[i-1]*i%mod; inv[i]=pw(fac[i],mod-2); } solve(n-1); int ans=0; for(int i=1;i<=n&&i<=m;++i){ int tmp=(ll)f[n-i]*C(m-1,i-1)%mod; inc(ans,tmp); } cout<<ans<<endl; return 0; }