• 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;
    }
  • 相关阅读:
    CF960G-Bandit Blues【第一类斯特林数,分治,NTT】
    P6122-[NEERC2016]Mole Tunnels【模拟费用流】
    P5404-[CTS2019]重复【KMP,dp】
    P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】
    T183637-变异距离(2021 CoE III C)【单调栈】
    61-A
    2021-4-1考试
    JAVA日常练习—程序输入string转化为int并求和
    并发编程
    git clone 报filename too long 错误的解决方法
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2889947.html
Copyright © 2020-2023  润新知