HDU 5201 The Monkey King

题目大意:把n个桃子给m个不同的猴子,第一个必须拿严格最多,求方案数

具体思路:首先考虑没有限制的情况,好像插个隔板就好了呢

然后我们可以枚举第一个猴子的拿桃数,

于是我们可以求出第一个猴子的拿桃数已知的总方案

然后减去不合法的就好了

怎么减勒?我们枚举有几个猴子拿的桃比大王多,然后用组合数求出有几种取法,在一顿乱搞就好了

于是貌似重复了耶,结果发现如果有两个猴子拿的桃比大王多,这个情况会被在前面算2次,那么我们减掉

如果有三个猴子拿的桃比大王多,这个情况会被在前面算0次,我们把它加上

...

于是从1开始一个加一个减就好了(不会证)

AC代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int ha=1000000007;
int n,m,fact[200010],factinv[200010],inv[200010],ans,T;
int INV(int x)
{
    int ans=1,b=ha-2,a=x;
    while (b)
    {
        if(b&1)ans=ans*a%ha;
        b=b/2;a=a*a%ha;
    }
    return ans;
}
int C(int x,int y){return fact[x]*factinv[y]%ha*factinv[x-y]%ha;}
int F(int x,int y){return C(x+y-1,y-1);}
signed main()
{
    fact[0]=1,factinv[0]=1,scanf("%lld",&T);
    for (register int i=1;i<=200000;i++)fact[i]=fact[i-1]*i%ha,inv[i]=INV(i),factinv[i]=factinv[i-1]*inv[i]%ha;
    while(T--)
    {
        scanf("%lld%lld",&n,&m),ans=F(n,m);
        for (register int i=0;i<=n;i++)
            for (register int j=1;j<=m&&i*(j+1)<=n;j++)(j%2)?ans=(ans-C(m-1,j)*F(n-i*(j+1),m-1)%ha+ha)%ha:ans=(ans+C(m-1,j)*F(n-i*(j+1),m-1)%ha)%ha;
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Orange-User/p/7751665.html