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
原文地址:https://www.cnblogs.com/TreeDream/p/5890244.html