uva 10910 Marks Distribution

数学题(组合数学 或者 DP递推都可以)

题意就不说了比较好懂。

这题如果按照题意去模拟着思考是很难解决的,我们换一种思维,抓住一个特殊条件,将问题进行转化。无论是组合数学的方法计算还是DP递推,都是转化问题后才进行的。我们看做有n个不同的盒子,很t个完全相同重量为1的球。按照题意,每个盒子的重量不能小于p,那么我们干脆先每个盒子都放p个小球。剩下m=t-n*p个小球。那么无论这m个小球怎么放都是符合要求的。所以问题就转化为,将m个完全相同的小球放在n个不同的盒子里,盒子内可以装一个或多个小球或者为空。

 

组合数学:

即便是“将m个完全相同的小球放在n个不同的盒子里,盒子内可以装一个或多个小球或者为空”,这样的问题都不好办。我们再将问题转化,可以看作一共有m+n-1个相同的盒子,从中抽出m个,那么将剩下n-1个盒子,n-1个盒子会产生n个空隙,其实这个就是原问题,可以看做抽出来的这m个盒子就来自于这n个空隙。  所以我们要求的就是 C(m,m+n-1)

#include <cstdio>

int n,t,p,m;



long long C(int a ,int b)

{

    if(b-a<a) a=b-a;

    long long ans=1;

    for(int i=1; i<=a; i++)

        ans=ans*(b-i+1)/i;

    return ans;

}

int main()

{

    int Case;

    scanf("%d",&Case);

    while(Case--)

    {

        scanf("%d%d%d",&n,&t,&p);

        m=t-n*p;

        n=n-1+m;

        printf("%lld\n",C(m,n));

    }

    return 0;

}

 

 

DP递推:“将m个完全相同的小球放在n个不同的盒子里,盒子内可以装一个或多个小球或者为空”

一开始想以球数为准进行递推,不难发现这样会重复,所以转化为以盒子为准递推

比如在前4个盒子里放10个球。若前3个盒子放了10个球,第4个盒子为空;若前3个盒子放了9个球,第4个盒子放1个球;若前3个盒子放了8个盒子,第4个盒子放2个球………………若前3个盒子放了0个球,那么第4个盒子放10个球

dp[i][j]表示在前i个盒子里放j个小球的方案数

方程为 dp[i][j]=dp[i-1][0]+dp[i-1][1]+dp[i-1][2]+dp[i-1][3]……+dp[i-1][j]

初始化dp[i][0]=1  ,不放盒子时只有唯一的可能

#include <cstdio>

#include <cstring>

#define N 75

int dp[N][N];



int main()

{

    int Case,n,t,p,m;

    scanf("%d",&Case);

    while(Case--)

    {

        scanf("%d%d%d",&n,&t,&p);

        m=t-n*p;

        memset(dp,0,sizeof(dp));

        for(int i=0; i<=n; i++) dp[i][0]=1;



        for(int i=1; i<=n; i++)

            for(int j=1; j<=m; j++)

                for(int k=0; k<=j; k++)

                    dp[i][j]+=dp[i-1][k];

        printf("%d\n",dp[n][m]);

    }

    return 0;

}

 

 

 

最后总结一下求C(a,b)的模板

long long C(int a ,int b)

{

    if(b-a<a) a=b-a;

    long long ans=1;

    for(int i=1; i<=a; i++)

        ans=ans*(b-i+1)/i;

    return ans;

}

 

你可能感兴趣的:(mark)