The Monkey King
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 365 Accepted Submission(s): 115
Problem Description
As everyone known, The Monkey King is Son Goku. He and his offspring live in Mountain of Flowers and Fruits. One day, his sons get
n
peaches. And there are
m
monkeys (including GoKu), they are numbered from
1
to
m
, GoKu’s number is 1. GoKu wants to distribute these peaches to themselves. Since GoKu is the King, so he must get the most peach. GoKu wants to know how many different ways he can distribute these peaches. For example n=2, m=3, there is only one way to distribute these peach: 2 0 0.
When given n and m , you are expected to calculate how many different ways GoKu can distribute these peaches. Answer may be very large, output the answer modular 1000000007 instead.
When given n and m , you are expected to calculate how many different ways GoKu can distribute these peaches. Answer may be very large, output the answer modular 1000000007 instead.
Input
There are multiple test cases. In the first line of the input file there is an integer
T
indicates the number of test cases.
In the next T lines, each line contains n and m which is mentioned above.
[Technical Specification]
All input items are integers.
1≤T≤25
1≤n,m≤100000
In the next T lines, each line contains n and m which is mentioned above.
[Technical Specification]
All input items are integers.
1≤T≤25
1≤n,m≤100000
For each case,the output should occupies exactly one line.
See the sample for more details.
See the sample for more details.
2 2 2 3 5
1 5HintFor the second case, there are five ways. They are 2 1 0 0 0 2 0 1 0 0 2 0 0 1 0 2 0 0 0 1 3 0 0 0 0
Source
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5201
题目大意:m个猴子分n个桃,要求第一个猴子的桃数严格大于其他猴子,问有多少种分法
题目分析:如果不考虑,限制条件,m个猴子分n个桃,且每个猴子可能分不到桃,则问题转化为部不定方程非负整数解的个数问题,设每个猴子得到的桃子为ai,则:
a1+a2+...+am <= n,(ai >= 0且ai为整数),用隔板法可以算出答案为C(n + m - 1, m - 1),现在考虑第一只猴子的桃数严格最大的条件,因为至少有k个猴子的桃数大于等于第一个猴子的情况很好算,即假设给了第一支猴子x个桃,先C(m-1, k),从剩下的m-1个猴子里选出k个猴子,每个猴子都给x个桃,那么还剩n - (k + 1) * x个桃,把这些桃再分给除了第一个猴子的剩下m-1个猴子的方案数还是之前那个公式,最后容斥一下,第一只猴子桃数最大的方案=总方案-至少一个猴子比第一个猴子多的方案数+至少二个猴子比第一个猴子多的方案数-...,典型容斥,注意判断组合数的边界,还有这题组合数很大,可以用费马小定理预处理组合数公式里分母上阶乘的逆元,来求组合数
#include <cstdio>
#define ll long long
int const MAX = 2e5 + 5;
int const MOD = 1e9 + 7;
ll f[MAX], f_inv[MAX];
int n, m;
ll qpow(ll x, ll n)
{
ll res = 1;
while(n)
{
if(n & 1)
res = (res * x) % MOD;
x = (x * x) % MOD;
n >>= 1;
}
return res;
}
void Init()
{
f[0] = f_inv[0] = 1;
f[1] = f_inv[1] = 1;
for(ll i = 2; i < MAX; i++)
{
f[i] = i * f[i - 1] % MOD;
f_inv[i] = qpow(f[i], MOD - 2);
}
}
ll C(ll i, ll j)
{
return f[i] * f_inv[j] % MOD * f_inv[i - j] % MOD;
}
ll F(int i, int j)
{
return C(i + j - 1, j - 1);
}
ll cal(int x)
{
if(x == n)
return 1;
ll res = 0, i = 0;
while(true)
{
if(i > m - 1)
break;
ll rest = n - (i + 1) * x;
if(rest < 0)
break;
ll tmp = C(m - 1, i) * F(rest, m - 1) % MOD;
if(i & 1)
res = (MOD + res - tmp) % MOD;
else
res = (res + tmp) % MOD;
i ++;
}
return res;
}
int main()
{
Init();
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d %d", &n, &m);
if(m == 1)
{
printf("1\n");
continue;
}
ll ans = 0;
for(int i = 1; i <= n; i++)
ans = (ans % MOD + cal(i) % MOD) % MOD;
printf("%I64d\n", ans);
}
}