Description
Input
Output
Sample Input
样例一:3 2 1
样例二:15 6 4
Sample Output
样例一:10
样例二:458177764
Data Constraint
Hint
样例一解释:
Solution
对于这种求方案数的问题,我们考虑DP。
我们考虑逐个位置填区间,比如说做到了第 i i 个容器。
那么在填了的区间(设共有 个)中,肯定有些已经闭合了,有些尚未闭合(设为 k k 个)。
那么我们就得到了状态 表示此时的方案数,显然 f[0][0][0]=1 f [ 0 ] [ 0 ] [ 0 ] = 1 。
如何转移呢?我们想想这时我们可以做什么,闭合某些尚未闭合的区间,开启新的未闭合的区间。
于是我们枚举两个值 dec,inc d e c , i n c 分别表示此时闭合区间的数量和将要开启新区间的数量。
由于这 K K 个区间是互不相同的,我们要需要处理出其顺序带来的方案数。
那么显然有转移式:
其中 Cdeck C k d e c 表示在 k k 个未闭合的区间中选择 来闭合增加的组合方案。
而 Cincj+inc C j + i n c i n c 表示新增的 inc i n c 个区间在总共的 j+inc j + i n c 个区间中的排列顺序增加的组合方案。
而每个容器的容量为 T T 的限制就相当于在任意时刻未闭合的区间数量不超过 。
答案即为 f[n+1][k][0] f [ n + 1 ] [ k ] [ 0 ] 。
时间复杂度 O(NK4) O ( N K 4 ) 。
Code
#include<cstdio>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=45,mo=1011110011;
int n,k,T;
int f[N][N][N],c[N][N];
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
int main()
{
freopen("container.in","r",stdin);
freopen("container.out","w",stdout);
n=read(),k=read(),T=read();
for(int i=0;i<N;i++) c[i][0]=1;
for(int i=1;i<N;i++)
for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
f[0][0][0]=1;
for(int i=0;i<=n;i++)
for(int j=0;j<=k;j++)
for(int l=0;l<=j && l<=T;l++)
if(f[i][j][l])
for(int inc=0;j+inc<=k;inc++)
for(int dec=0;dec<=l;dec++)
if(l-dec+inc<=T)
f[i+1][j+inc][l-dec+inc]=(f[i+1][j+inc][l-dec+inc]+
(LL)f[i][j][l]*c[l][dec]%mo*c[j+inc][inc]%mo)%mo;
printf("%d",f[n+1][k][0]);
return 0;
}