lightoj 1145 - Dice (I)

本文探讨了给定n个骰子,每个骰子有k个面时,求所有可能的摆放方式使得骰子面朝上的数字之和为特定值s的问题。采用动态规划方法进行解答,并使用前缀和与滚动数组技巧优化算法的时间与空间复杂度。

You have N dices; each of them has K faces numbered from 1 to K. Now you have arranged the N dices in a line. You can rotate/flip any dice if you want. How many ways you can set the top faces such that the summation of all the top faces equals S?

Now you are given N, K, S; you have to calculate the total number of ways.

Input

Input starts with an integer T (≤ 25), denoting the number of test cases.

Each case contains three integers: N (1 ≤ N ≤ 1000), K (1 ≤ K ≤ 1000) and S (0 ≤ S ≤ 15000).

Output

For each case print the case number and the result modulo 100000007.

Sample Input

Output for Sample Input

5

1 6 3

2 9 8

500 6 1000

800 800 10000

2 100 10

Case 1: 1

Case 2: 7

Case 3: 57286574

Case 4: 72413502

Case 5: 9



题意:n,k,s代表有n个骰子,每个骰子有k个面,问你有多少种摆放方式使他们的和等于s。

思路:如果用dp[i][j]代表前i个骰子的和是j的方法数,那么状态转移公式应该就是dp[i][j] = dp[i-1][j-1] + dp[i-1][j-2] + .... + dp[i-1][j-k],如果这样三重循环,时间肯定爆炸,所以我们可以用前缀和来优化一下。每次加上一个,再减去一个dp[i-1][j-k],如果j-k小于0,那么dp[i-1][j-k]就是0。

还有一点就是空间也会超,所以用滚动数组。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 1e9
#define endl '\n'
#define mod 100000007
#define LL long long

using namespace std;


LL dp[2][15010];

int main(void)
{
    int T,n,k,s,i,j;
    scanf("%d",&T);
    int cas = 1;
    while(T--)
    {
        scanf("%d%d%d",&n,&k,&s);
        memset(dp,0,sizeof(dp));
        dp[0][0] = 1;
        int x = 1;
        for(i=1;i<=n;i++)
        {
            x ^= 1;
            LL sum = 0;
            for(j=0;j<=s;j++)
            {
                dp[x^1][j] = sum;
                if(j - k < 0)
                    sum = (sum + dp[x][j])%mod;
                else
                    sum = ((sum + dp[x][j] - dp[x][j-k])%mod+mod)%mod;
            }
        }
        printf("Case %d: %lld\n",cas++,dp[x^1][s]);
    }
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值