您的位置:首页 > 其它

UVA - 10313 Pay the Price

2013-09-22 16:45 281 查看
题意:在1-300之间,给你n,如果后面没跟着数字,代表用1-n的的种数凑成n,如果有一个数的话代表用1-l1种数凑成n,如果还有l2,代表用种数大于l1,小于l2的数凑成n,这貌似没思路啊,枚举的话好像不是太可能啊,后来看到这题涉及到一个结论ferrers图的性质:数n拆分成k个数的和的拆分数,和数n拆分成最大数为k的拆分数相等,然后就用

dp[i][j]代表用大小不超过j的数凑成i的方法个数,还是选与不选的考虑,如果选j的话,dp[i][j] = dp[i-j][j],不选的话

dp[i][j] = dp[i][j-1],所以dp[i][j] = dp[i][j-1] + dp[i-j][j],当然如果i < j的话,那么就只能用j-1去凑,至于能不能凑又是之前的事啦

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 305;

long long dp[MAXN][MAXN];
char str[1000];

int main(){
    for (int i = 0; i <= 300; i++){
        dp[i][0] = i?0:1;   //初始化
        for (int j = 1; j <= 300; j++)
            if (i >= j)
                dp[i][j] = dp[i-j][j] + dp[i][j-1];
            else  
                dp[i][j] = dp[i][j-1];
    }
    while (gets(str)){
        int n,l1=-1,l2=-1;
        sscanf(str,"%d %d %d",&n,&l1,&l2);
        l1 = min(l1,300);
        l2 = min(l2,300);
        if (l1 == -1)
            printf("%lld\n",dp

);
        else if (l2 == -1)
            printf("%lld\n",dp
[l1]);
        else {
            if (l1 == 0)
                printf("%lld\n",dp
[l2]);
            else printf("%lld\n",dp
[l2]-dp
[l1-1]);
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: