JZOJ 5192. 【NOI2017模拟7.2】容器

Description

Description

Input

Input

Output

Output

Sample Input

样例一:3 2 1
样例二:15 6 4

Sample Output

样例一:10
样例二:458177764

Data Constraint

Data Constraint

Hint

样例一解释:
Hint

Solution

  • 对于这种求方案数的问题,我们考虑DP。

  • 我们考虑逐个位置填区间,比如说做到了第 i 个容器。

  • 那么在填了的区间(设共有 j 个)中,肯定有些已经闭合了,有些尚未闭合(设为 k 个)。

  • 那么我们就得到了状态 f [ i ] [ j ] [ k ] 表示此时的方案数,显然 f [ 0 ] [ 0 ] [ 0 ] = 1

  • 如何转移呢?我们想想这时我们可以做什么,闭合某些尚未闭合的区间,开启新的未闭合的区间。

  • 于是我们枚举两个值 d e c , i n c 分别表示此时闭合区间的数量和将要开启新区间的数量。

  • 由于这 K 个区间是互不相同的,我们要需要处理出其顺序带来的方案数。

  • 那么显然有转移式:

    f [ i ] [ j ] [ k ] C k d e c C j + i n c i n c => f [ i + 1 ] [ j + i n c ] [ k d e c + i n c ]

  • 其中 C k d e c 表示在 k 个未闭合的区间中选择 d e c 来闭合增加的组合方案。

  • C j + i n c i n c 表示新增的 i n c 个区间在总共的 j + i n c 个区间中的排列顺序增加的组合方案。

  • 而每个容器的容量为 T 的限制就相当于在任意时刻未闭合的区间数量不超过 T

  • 答案即为 f [ n + 1 ] [ k ] [ 0 ]

  • 时间复杂度 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;
}

猜你喜欢

转载自blog.csdn.net/liyizhixl/article/details/80321109