acdream 1014 Dice Dice Dice(组合)

系统 1845 0

题目链接: http://www.acdream.net/problem.php?id=1014

题意:n个筛子,每个筛子m个面(标有数字1到m)。n个筛子前K大的筛子数字之和为p的有多少种?

思路:f[i][j][k][t]表示i分成j个数的和,j个数中最大的数为k,最小的数为t。计算的时候,枚举最大和最小的数字,再枚举在K个中最小数字出现的次数以及n-K个中最小数字出现的次数。

 

      
        #include <iostream>

#include <stdio.h>

#define i64 long long

#define max(x,y) ((x)>(y)?(x):(y))

#define min(x,y) ((x)<(y)?(x):(y))

using namespace std;





i64 f[245][25][15][15],C[25][25];



void init()

{

    int i,j,k,p,d;

    for(i=1;i<=12;i++) f[i][1][i][i]=1;

    for(j=1;j<=20;j++) for(i=0;i<=240;i++) for(k=0;k<=12;k++)

    {

        for(p=0;p<=k;p++) if(f[i][j][k][p]) for(d=1;d<=12&&i+d<=240;d++)

        {

            f[i+d][j+1][max(k,d)][min(p,d)]+=f[i][j][k][p];

        }

    }

    for(i=1;i<=20;i++)

    {

        C[i][0]=C[i][i]=1;

        for(j=1;j<i;j++) C[i][j]=C[i-1][j]+C[i-1][j-1];

    }

}



int n,m,K,p;



i64 POW(i64 a,i64 b)

{

    i64 ans=1;

    while(b)

    {

        if(b&1) ans=ans*a;

        a=a*a;

        b>>=1;

    }

    return ans;

}



int main()

{

    init();

    while(scanf("%d%d%d%d",&n,&m,&K,&p)!=-1)

    {

        if(p>K*m)

        {

            puts("0");

            continue;

        }

        i64 ans=0,i,j,k,t,cnt1,cnt2;

        for(i=1;i<=m;i++) for(j=1;j<=i&&j*K<=p;j++)

        {

            for(cnt1=1;cnt1*j<=p&&cnt1<=K;cnt1++) for(cnt2=0;cnt2<=n-K;cnt2++)

            {

                k=0;

                if(cnt1*j==p)

                {

                    if(i==j) k=1;

                    else continue;

                }

                else

                {

                    for(t=j+1;t<=i;t++) k+=f[p-cnt1*j][K-cnt1][i][t];

                }

                ans+=k*C[n][K-cnt1]*C[n-(K-cnt1)][cnt1+cnt2]*POW(j-1,n-K-cnt2);

            }

        }

        printf("%lld\n",ans);

    }

    return 0;

}


      
    

 

 

acdream 1014 Dice Dice Dice(组合)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论