In an examination one student appeared in N subjects and has got total T marks. He has passed in all the Nsubjects where minimum mark for passing in each subject is P. You have to calculate the number of ways the student can get the marks. For example, if N=3, T=34 and P=10 then the marks in the three subject could be as follows.
Subject 1 |
Subject 2 |
Subject 3 |
|
1 |
14 |
10 |
10 |
2 |
13 |
11 |
10 |
3 |
13 |
10 |
11 |
4 |
12 |
11 |
11 |
5 |
12 |
10 |
12 |
6 |
11 |
11 |
12 |
7 |
11 |
10 |
13 |
8 |
10 |
11 |
13 |
9 |
10 |
10 |
14 |
10 |
11 |
12 |
11 |
11 |
10 |
12 |
12 |
12 |
12 |
12 |
10 |
13 |
10 |
13 |
11 |
14 |
11 |
13 |
10 |
15 |
10 |
14 |
10 |
So there are 15 solutions. So F (3, 34, 10) = 15.
Input
In the first line of the input there will be a single positive integer K followed by K lines each containing a single test case. Each test case contains three positive integers denoting N, T and P respectively. The values of N, T and P will be at most 70. You may assume that the final answer will fit in a standard 32-bit integer.
Output
For each input, print in a line the value of F (N, T, P).
Sample Input |
Output for Sample Input |
2 |
15 |
分析:
解法一:组合数学
这个问题可以转化为把m个物体放到n个盒子里面,允许有的盒子为空,问一共有多少种放置方法。因为除去每门课必须的P以后,剩下的M=T-N*P可以随意分配到N门课程里面。这样问题就变成了“插板法”的经典应用。分成N组需要N-1个隔板,再加上M个物体,可以看成N-1+M个空隙,然后从这些空隙中选出N-1用来放隔板,共有C(N-1+M,N-1)中种方法。
#include <cstdio> typedef long long LL; LL C(LL n, LL k) { if(n - k < k) k = n - k; //防止数据溢出 LL ans = 1; for(int i = 1; i <= k; i++) ans = ans * (n - i + 1) / i; return ans; } int main() { int cas; LL n, t, p; scanf("%d", &cas); while(cas--) { scanf("%lld%lld%lld", &n, &t, &p); t = t - n * p; LL ans = C(n + t - 1, n - 1); printf("%lld\n", ans); } return 0; }
用a[i][j]表示前i个盒子里面放了j个物体的放法,则a[i][j] = a[i-1][0] + a[i-1][1] + …… + a[i-1][j].
初始化dp[i][0] = 1。
#include <cstdio> #include <cstring> const int N = 72; typedef long long LL; LL a[N][N]; int main() { int T; LL n, p, t; scanf("%d", &T); while(T--) { scanf("%lld%lld%lld", &n, &t, &p); t = t - n * p; memset(a, 0, sizeof(a)); for(int i = 0; i <= n; i++) a[i][0] = 1; for(int i = 1; i <= n; i++) { for(int j = 1; j <= t; j++) { for(int k = 0; k <= j; k++) a[i][j] += a[i-1][k]; } } printf("%lld\n", a[n][t]); } return 0; }