【xsy2425】容器 dp
题目大意:有$n$个人,区间大小为$m$,每个人必须覆盖一段区间$[l_i,r_i]$,问你存在多少种不同的覆盖方案,使得区间上每个位置被覆盖的次数不超过$t$。
两种方案被定义为不同当且仅当存在第i个人覆盖的区间不同。
求方案数,对一个质数取模。
数据范围:$n,m,t≤40$
我们考虑dp。
设$f[i][j][k]$表示区间的前i个位置,总共有$j$个人参与了覆盖,且有$k$个人同时覆盖了位置$i$,位置$i+1$的方案数。
我们考虑枚举$J$和$K$,需要保证$j<J$
那么我们显然可以用f[i][j][k]的值去更新$f[i+1][J][K]$的值。
从$f[i][j][k]$到$f[i+1][J][K]$,用的人数多了$J-j$个,我们要从$n-j$个人中选出$J-j$个人去增加总人数,方案数显然为$\binom {n-j}{J-j}$。
然后,我们还要保证有$K$个人可以覆盖到$i+2$,而这$K$个人显然只能从$k+(J-j)$个人中选出,方案数显然为$\binom {k+(J-j)}{K}$。
那么转移方程大概长这样:
$f[i+1][J][K]+=f[i][j][k]\times \binom{n-j}{J-j}\times \binom{J-j+k}{K}$
复杂度为$O(nk^4)$
1 #include<bits/stdc++.h> 2 #define L long long 3 #define M 55 4 #define MOD 1011110011 5 using namespace std; 6 7 L n,m,t,c[M][M]={0},f[M][M][M]={0}; 8 9 int main(){ 10 for(int i=0;i<M;i++){ 11 c[i][0]=1; 12 for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD; 13 } 14 cin>>n>>m>>t; 15 f[0][0][0]=1; 16 for(int i=0;i<n;i++) 17 for(int j=0;j<=m;j++) 18 for(int k=0;k<=j;k++) 19 if(f[i][j][k]){ 20 for(int J=j;J<=m;J++) 21 for(int K=0;K<=J;K++){ 22 int cnt=J-j+k; 23 if(cnt>t) continue; 24 (f[i+1][J][K]+=f[i][j][k]*c[m-j][J-j]%MOD*c[cnt][K]%MOD)%=MOD; 25 } 26 } 27 cout<<f[n][m][0]<<endl; 28 }