• ural 1114,计数dp


    题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1114

    题意:N个盒子,a个红球,b个蓝球,把求放到盒子中去,没有任何限制,有多少种放法。

    刚开始我想数学方法啊!想了半天,情况太多了。偷偷搜了一下这个题目,DP,好的,两分钟DP方程出来了。

    dp[i][j][k] 表示前i个盒子,用掉了j个红球,k个蓝球,马上dp方程 dp[i][j][k] =∑ dp[i-1][m][n],m=[0,j],n=[0,k];初始化dp[0][0][0] = 1;

    要指出的是: 网上有很多解法,m,n的范围是反的,但是也能AC,如果按照这个思路是肯定不对的,至于为啥能AC,我想到了,很多人也许和我的思路刚好相反,他是想把dp[i][j][k] 是还有j个红球没有用,k个蓝球没有用,那么这样的话,循环得反着来,而且初始化应该是dp[0][a][b] = 1;

    然而,我这里想提的是,LJH大神的,他就是反着来的,但是超级厉害的地方是,他没有枚举j,k,也就是说没有5层循环,Orz.

    用一个数组tsum记录红球k的方案下的答案,sum更新蓝球k的方案下的答案,这样dp[i][j][k] 就可以利用以前的dp[i-1][j][k] 的答案了,只需要不断更新sum,tsum[k],

    #include <bits/stdc++.h>
    using namespace std;
    
    unsigned long long dp[30][25][25];
    unsigned long long tsum[25];
    
    int main()
    {
        int n,a,b;
        scanf("%d%d%d",&n,&a,&b);
        dp[0][0][0] = 1;
    
        unsigned sum = 0;
    
        for(int i=1;i<=25;i++)
        {
            for(int j=0;j<=20;j++)
            {
                for(int k=0;k<=20;k++)
                {
                    for(int jj = 0;jj<=j;jj++)
                        for(int kk = 0;kk<=k;kk++)
                            dp[i][j][k] += dp[i-1][jj][kk];
                }
            }
        }
    
        unsigned long long ans = 0;
        for(int i=0; i<=a; i++)
            for(int j=0; j<=b; j++)
                ans +=dp[n][i][j];
        printf("%I64u
    ",ans);
    
        return 0;
    }
    View Code
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<deque>
    #include<functional>
    #include<iterator>
    #include<set>
    #include<utility>
    #include<stack>
    #include<queue>
    #include<iomanip>
    using namespace std;
    
    typedef unsigned long long ll;
    
    ll dp[21][16][16];
    ll tsum[16];
    int main()
    {
        int n;
        int a,b;
        ll sum;
        cin>>n>>a>>b;
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1;
        for(int i=1;i<=n;++i)
        {
            memset(tsum,0,sizeof(tsum));
            for(int j=0;j<=a;j++)
            {
                sum=0;
                for(int k=0;k<=b;k++)
                {
                    sum+=dp[i-1][j][k];
                    tsum[k]+=sum;
                    dp[i][j][k]=tsum[k];
    
                }
            }
        }
    
        sum=0;
        for(int i=0;i<=a;++i)
            for(int j=0;j<=b;++j)
                sum+=dp[n][i][j];
        cout<<sum<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    Android测试AsyncTask下载图片
    Android DatePickerDialog TimepickerDialog
    Android AlertDialog
    Android activity的回传数据
    Android Handler简单使用
    Java Switch(String)
    JAVA测试装饰者模式
    Java实现数组按数值大小排序
    Java参数按值传递?按引用传递
    Spring cloud之断路器hystrix包问题
  • 原文地址:https://www.cnblogs.com/TreeDream/p/5890244.html
Copyright © 2020-2023  润新知