[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 } 
View Code

 

posted @ 2021-12-12 16:40  PYWBKTDA  阅读(144)  评论(0编辑  收藏  举报