hdu 5201 The Monkey King(容斥原理,排列组合)

来源:互联网 发布:jquery清空input数据 编辑:程序博客网 时间:2024/06/09 16:53

The Monkey King

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 442    Accepted Submission(s): 148


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 mmonkeys (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.
 

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.

1T25

1n,m100000
 

Output
For each case,the output should occupies exactly one line.

See the sample for more details.
 

Sample Input
22 23 5
 

Sample Output
15
Hint
For the second case, there are five ways. They are2 1 0 0 02 0 1 0 02 0 0 1 02 0 0 0 13 0 0 0 0
 

Source
BestCoder Round #36 ($)

题意:有n个桃子m只猴子,第一只猴子的桃子要严格大于其他猴子,问一共有几种方案

思路:首先我们假设第一只猴子取了x个桃子,那么剩下的猴子一共有n-x个桃子,不考虑严格大于,一共有F(n-x,m-1)种情况

F(a,b)表示把a件物品分给b个人(某个人可能分到0)的方案数。用高中时候学过的隔板法可以知道F(a,b)=C(a+b-1,a)

相当于在所有的桃子中间插b-1块隔板,每两块(或一块与边界)组成一个人所得的东西。

那么此时我们是要求所有不合法的情况数,那么我们又知道,假设有k个猴子所得桃子>=1号桃子

那么情况数是C(m-1,k)*F(n-(k+1)*x,m-1)相当于先取出k个x,然后分配给m-1只猴子,最后把k个x加到m-1只猴子里面的任意k只里面

我们求出来的是>=k只猴子的方案数,那么如何得到所有的方案数呢?  如果直接从1开始累加,很明显会有重复的(1里面可能有2,3...的情况)(对于那k只之外的,我们无法确定他们与x的关系,所以可能会包含重复的)

所以这里就是典型的容斥原理了。

从1开始减一个加一个即可~

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;#define N 200050#define mod 1000000007long long inv[N],f[N];///f表示阶乘,inv是阶乘逆元long long pow_mod(long long a,long long n){    long long ans=1;    while(n)    {        if(n&1) ans=ans*a%mod;        a=a*a%mod;        n>>=1;    }    return ans;}long long C(long long a,long long b){    if(a<b||a<0||b<0) return 0;    return f[a]*inv[b]%mod*inv[a-b]%mod;}long long F(long long a,long long b){    return C(a+b-1,a);}int main(){    int T;    long long n,m;    f[0]=inv[0]=1;    for(long long i=1; i<N; i++)    {        f[i]=f[i-1]*i%mod;        inv[i]=pow_mod(f[i],mod-2);    }    scanf("%d",&T);    while(T--)    {        scanf("%lld %lld",&n,&m);        if(n==1||m==1)        {            printf("1\n");            continue;        }        long long ans=0;        for (long long x=1; x<=n; x++)        {            ans=(ans+F(n-x,m-1))%mod;            for (long long k=1; n-(k+1)*x>=0; k++)            {                long long tmp = C(m-1, k) * F(n-(k+1)*x, m-1) % mod;                if (k%2==0) ans = (ans + tmp) % mod;                else ans = (ans - tmp + mod) % mod;            }        }        printf("%lld\n",ans);    }    return 0;}







0 0