【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$个人去增加总人数,方案数显然为$inom {n-j}{J-j}$。

然后,我们还要保证有$K$个人可以覆盖到$i+2$,而这$K$个人显然只能从$k+(J-j)$个人中选出,方案数显然为$inom {k+(J-j)}{K}$。

那么转移方程大概长这样:

$f[i+1][J][K]+=f[i][j][k] imes inom{n-j}{J-j} imes inom{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 }
原文地址:https://www.cnblogs.com/xiefengze1/p/10626488.html