题目
描述
有一个纸片,纸片上有\(n\)个格子,初始时没有颜色;
某个游戏的内容是进行\(m\)次染色,使得染完后\(n\)个格子一定有颜色;
每次可以选择一个区间\([l,r](l \le r)\)去染(不能不染),颜色可以覆盖;
问最后染出的序列有多少种;
范围
\(n,m \le 10^6\) ;
题解
由于可以覆盖这个条件处理起来比较麻烦;
考虑每次是插入一段颜色;
\[ \begin{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} \times (j+1)\),一种是\(f_{i,j}\times 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; }