HDU 5201 The Monkey King 组合数+不定方程解的个数

来源:互联网 发布:数据库接口什么样的 编辑:程序博客网 时间:2024/05/16 06:25

题意:链接

方法:组合数+不定方程解的个数

解析:

毒瘤题,好难啊,刷一个我就不想再刷另外两个了

这里写图片描述

这玩意的话,后俩先不看。

先看前两个。

前两个是啥意思呢。

不妨考虑一下挡板法。

这里我举一个某篇我想不起名字的论文的方法。

首先看这个不定方程

x+y+z=20

我们设一个字符串aaaaaaaaaaaaaaaaaaaa

恰好20个a,现在来给x,y分配。

则该求解该不定方程的正整数解的个数相当于将串变成了:

asasasasasasasasasasasasasasasasasasasa

20个a,19个s

从中任意选出两个S

则答案显然为C219

这也就恰好对应了上文的Cn1m1

然后现在我们来考虑该不定方程的非负整数解的个数。

换一种假设方式。

现在假设有20个白球,2个黑球。

则这22个球的排列方案数对应着该不定方程的解的个数。

很显然嘛。

你可以画一下俩黑球在队首队尾的特殊情况理解一下就好了。

也可以想这两个黑球将一个线段分成了三部分。

总之这个不是什么难的地方。

于是答案对应是什么呢?

C222

即公式里对应的Cn1n+m1


第三个公式我还没咋看,没研究,再说这道题跟这个也没关系,所以先挖坑


第四个公式的话其实就是个容斥原理!

枚举,n个数里面有多少个大于等于k+1个数。

那么这显然是个容斥。

设F(i)表示n个数里有i个大于等于k+1

ans=F(0)F(1)+F(2)F(3).....


好,现在来说这道题。

我们枚举第一个猴子能取多少个桃。

倒序枚举+一个剪枝即可

然后现在对于剩下的方程是这个形式。

X2+X3+...+Xn=mX1Xi(i[2,n])<=X1

裸上公式四。

然后我们来观察一下复杂度。

其实这个东西的复杂度是

ni=1ni

这是啥?->级数求和啊。

O(nlogn)啊

然后预处理是O(nlogmod)的

显然能过。

代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 100100#define mod 1000000007using namespace std;typedef long long ll;int t;int n,m;ll factor[N<<1];ll invfactor[N<<1];ll get_inv(ll x,ll y){    ll ret=1;    while(y)    {        if(y&1)ret=(ret*x)%mod;        x=(x*x)%mod;        y>>=1;     }    return ret;}void init_factor(){    factor[0]=1,factor[1]=1,invfactor[1]=1,invfactor[0]=1;    for(int i=2;i<=200000;i++)    {        factor[i]=(factor[i-1]*i)%mod;        invfactor[i]=get_inv(factor[i],mod-2);    }   }ll get_C(int n,int m){    if(m==0)return 1;    return factor[n]*invfactor[m]%mod*invfactor[n-m]%mod; } ll get_ans(int n,int m){    //x1+x2+x3+..+xm==n    //x1最大    ll ret=0;    if(n==0)return 0;    if(n==1)return 1;    if(m==1)return 1;    for(int i=n;i>0;i--)    {        if(i<=(n-i)/(m-1)+((n-i)%(m-1)==0?0:1))break;        int tmpn=n-i,tmpm=m-1;        ll ans=0;        for(int j=0;j<=tmpm&&j*i<=tmpn;j++)        {            ll caltmp=get_C(tmpm,j)*get_C(tmpn-j*i+tmpm-1,tmpm-1)%mod;            if(j%2==0)ans=(ans+caltmp)%mod;            else ans=((ans-caltmp)%mod+mod)%mod;         }        ret=(ret+ans)%mod;     }    return ret;}int main(){    init_factor();    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        printf("%I64d\n",get_ans(n,m));    }}
0 0