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]);
}
}