LightOJ 1193 Dice (II)(前缀和优化dp)

1193 - Dice (II)
Time Limit: 3 second(s)Memory Limit: 32 MB

You have N dices; each of them has K faces numbered from 1 to K. Now you can arrange the N dices in a line. If the summation of the top faces of the dices is S, you calculate the score as the multiplication of all the top faces.

Now you are given N, K, S; you have to calculate the summation of all the scores.

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) 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: 3

Case 2: 84

Case 3: 74335590

Case 4: 33274428

Case 5: 165



题意:有n枚有顺序的色子,有k面,若色子的点数和为s,求其乘积,最后求所有点数和为s的乘积的和
题解:该题为dp,网上其他题解都写得好复杂。。。但是我推出来为毛就那么简单
和其他题解的一样,先设dp【i】【j】为前i个色子的点数和为j的所有乘积和
        那么就有,dp【i】【j】=∑dp【i-1】【j-l】*l,其中l∈【1,k】
                    即,dp【i】【j】=                                     dp【i-1】【j-1】*1+dp【i-1】【j-2】*2+……+dp【i-1】【j-k+1】*(k-1)+dp【i-1】【j-k】*k
 将j换成j+1有,dp【i】【j+1】=dp【i-1】【j】*1+dp【i-1】【j-1】*2+dp【i-1】【j-2】*3+……+dp【i-1】【j-k+1】*k
那么就有递推,dp【i】【j+1】=dp【i】【j】+dp【i-1】【j】+……+dp【i-1】【j-k+1】-dp【i-1】【j-k】*k
若设sum【j】=dp【i-1】【1】+dp【i-1】【2】+……+dp【i-1】【j】
那么递推转移公式改写成,dp【i】【j+1】=dp【i】【j】+sum【j】-sum【j-k】-dp【i-1】【j-k】*k
需要注意的是,上式2个减去的部分需要判断j-k是否大于0,若否则不需要减
那么现在已经可以在O(1)时间内转移了,所以时间复杂度为O(n*s)
另外,由于内存不够,而且当前dp值只与上一行的dp值有关,所以数组用滚动的就行了

#include<stdio.h>
#include<string.h>
#define mod 100000007
long long dp[2][15008];
long long sum[15008];
int main()
{
    int t,n,k,s,i,j,now,cas=1;

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&k,&s);
        memset(dp,0,sizeof(dp));
        for(i=1;i<=k;i++) dp[1][i]=i;
        for(i=2; i<=n; i++)
        {
            now=i&1;
            memset(sum,0,sizeof(sum));
            for(j=1; j<=s; j++)
            {
                sum[j]=(sum[j-1]+dp[now^1][j])%mod;
                dp[now][j]=(dp[now][j-1]+sum[j-1])%mod;
                if(j>k) dp[now][j]=((dp[now][j]-sum[j-k-1]-dp[now^1][j-k-1]*k)%mod+mod)%mod;
            }
        }
        printf("Case %d: %lld\n",cas++,dp[n&1][s]);
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值