[cf1608F]MEX counting
定义$f_{i,x,s}$表示仅考虑$\{a_{1},a_{2},...,a_{i}\}$,当前${\rm mex}$为$x$且$a_{i}$中有$s$种不同的$>x$的值的方案数
需要注意的是,并不关心于这$s$种具体的值,即这些数仅仅是对$s$计数
考虑转移,根据定义不难得到即
$$
\begin{cases}\begin{cases}(x+s)f_{i-1,x,s}\rightarrow f_{i,x,s}\\f_{i-1,x,s}\rightarrow f_{i,x,s+1}\end{cases}&|x-b_{i}|\le k\\\forall |y-b_{i}|\le k,P_{s}^{y-x-1}f_{i-1,x,s}\rightarrow f_{i,y,s-(y-x-1)}\end{cases}
$$
进一步的,最终答案即$\sum P_{n-x}^{s}f_{n,x,s}$
考虑上述dp的复杂度,注意到$x$和$y$均是$o(k)$的,总复杂度即$o(n^{2}k^{2})$,无法通过
记$g_{i,x,s}=s!f_{i,x,s}$,那么上述转移也即变为
$$
\begin{cases}\begin{cases}(x+s)g_{i-1,x,s}\rightarrow g_{i,x,s}\\(s+1)g_{i-1,x,s}\rightarrow g_{i,x,s+1}\end{cases}&|x-b_{i}|\le k\\\forall |y-b_{i}|\le k,g_{i-1,x,s}\rightarrow g_{i,y,s-(y-x-1)}\end{cases}
$$
(类似地,最终答案即变为$\sum {n-x\choose s}g_{n,x,s}$)
前两个转移暴力实现即可,最后一个转移不难变形为$g_{i,x,s}=g_{i,x-1,s+1}+g_{i-1,x-1,s}$
另外,需要对最小的$x$暴力求出对应的值,再对更大的$x$计算
时间复杂度降为$o(n^{2}k)$,可以通过
另外,空间上可以对第一维滚动,空间复杂度降为$o(nk)$或$o(n^{2})$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2005 4 #define mod 998244353 5 #define ll long long 6 int n,m,ans,fac[N],inv[N],a[N],l[N],r[N],f[2][N][N]; 7 int C(int n,int m){ 8 if (n<m)return 0; 9 return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod; 10 } 11 int main(){ 12 fac[0]=inv[0]=inv[1]=1; 13 for(int i=1;i<N;i++)fac[i]=(ll)fac[i-1]*i%mod; 14 for(int i=2;i<N;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod; 15 for(int i=1;i<N;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod; 16 scanf("%d%d",&n,&m); 17 for(int i=1;i<=n;i++){ 18 scanf("%d",&a[i]); 19 l[i]=max(a[i]-m,0),r[i]=min(a[i]+m,i); 20 } 21 f[0][0][0]=1; 22 for(int i=1;i<=n;i++){ 23 int p=(i&1); 24 for(int k=0;k<=i-l[i];k++) 25 for(int j=max(l[i]-r[i-1]-1,0);j<l[i]-l[i-1];j++) 26 f[p][l[i]][k]=(f[p][l[i]][k]+f[p^1][l[i]-j-1][k+j])%mod; 27 for(int j=l[i]+1;j<=r[i];j++) 28 for(int k=0;k<=i-j;k++)f[p][j][k]=(f[p][j-1][k+1]+f[p^1][j-1][k])%mod; 29 for(int j=l[i-1];j<=r[i-1];j++) 30 for(int k=0;k<i-j;k++) 31 if ((l[i]<=j)&&(j<=r[i])){ 32 f[p][j][k]=(f[p][j][k]+(ll)(j+k)*f[p^1][j][k])%mod; 33 f[p][j][k+1]=(f[p][j][k+1]+(ll)(k+1)*f[p^1][j][k])%mod; 34 } 35 for(int j=l[i-1];j<=r[i-1];j++) 36 for(int k=0;k<i-j;k++)f[p^1][j][k]=0; 37 } 38 for(int i=0;i<=n;i++) 39 for(int j=0;j<=n-i;j++)ans=(ans+(ll)C(n-i,j)*f[n&1][i][j])%mod; 40 printf("%d\n",ans); 41 return 0; 42 }