hdu-6397(组合数学+抽屉原理)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6397

题意:共有m个取值范围为[0,n-1]的数字,求使得总和为k的方案数。

思路:链接:https://blog.csdn.net/yu121380/article/details/82802502

我们可以把k看成k个1,通过m-1个隔板来分割成m个数字。但是这样做会有问题,就是数字可能为0,但是隔板法不允许这种情况存在,所以我们可以做一个等价处理,即将取值范围+1,即[1,n],那么相应的总和也要加上m,即k+m,则问题转化为 “共有m个取值范围为[1,n]的数字,求使得总和为m+k的方案数”, 根据隔板法可以得出无限制的情况下方案数为 C(m+k-1, m-1)。

对于此题,共有ans=C(k+m-1,m),但此时,会出现有的数>=n,所以我们要将减掉  出现1数值>=n,(有C(m,1)种选法)2个数值>=n(有C(m,2)种选法).....(k/n,m)个数值大于等于n的情况 ,f(i)=C(k+m-n*i-1,m)....但减去f(1)时,会多减了f(2),f(3)......,所以要加上f(2),但此时又多加了f(3)....如此往复,发现,当i为奇数时,减去f(i),i为偶数时,加上f(i) 

这道题的k,就相当于有k个小球,放到m个盒子里,如果不考虑Xi的约束条件,答案就是。我们考虑,这些答案里会有某些,我们应该把这些情况去掉。当有一个的时候,有种Xi。此时就相当于k个小球中,已经有n个小球放到了某个盒子里,接下来把剩下的k-n个小球放到m个盒子里就是有这么多种情况。所以我们用,这样的话,多减去了有两个的情况,我们又要加回来。考虑到这里,就不难发现,这可以用容斥原理解决。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ull unsigned long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mems(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int N=2e5+10;
const double pi=acos(-1);
const int inf=0x3f3f3f3f;
const int M=50000+5;

ll n,m,k;
ll f[N],inv[N];
ll qpow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans%mod;
}

void init()
{
    f[0]=inv[0]=1;
    for(int i=1;i

   


 

你可能感兴趣的:(【容斥原理,抽屉原理】,【简单组合数学】)