2018 Multi-University Training Contest 8 1001 Character Encoding (hdu 6397)(容斥)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/81709195

题目链接:hdu 6397 Character Encoding

Sample Input
4
2 3 3
2 3 4
3 3 3
128 3 340
 

Sample Output
1
0
7
903

题意:给n,m,k,从0到n-1中取正好m个数字(可以重复取),求这m个数字之和为k的方案数 

思路:假设没有0到n-1这个限制条件,那么问题就变成k分为m份有几种方案,这是经典的组合数学问题,用隔板法,有C_{k+m-1}^{m-1}种方案数。当k小于等于n-1的时候,由于组合中不可能存在一个大于n-1的数字,所以答案就是C_{k+m-1}^{m-1},当k大于n-1的时候,我们需要去掉方案中含有n到k的数字的情况,这就需要用到容斥。容斥原理可以学习这篇博客,我也是看了这里的部分内容做这题的容斥原理详解

 我们假设A_{i}为i个数大于n-1的情况,与上述同理,已经有i*n个位置被占用了,所以\left | A_{i} \right |=C_{k-i*n+m-1}^{m-1}

那么最终结果即为A_{0}-C_{m}^{1}*A_{1}+C_{m}^{2}*A_{2}-C_{m}^{3}*A_{3}+......

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#define maxn 2000006
using namespace std;
typedef long long ll;
const ll mod=998244353;
 
ll b[maxn],inv[maxn],invf[maxn];
ll f[maxn];
int num[maxn];
ll sum[maxn];
ll mo(ll a,ll pp){
    if(a>=0&&a<pp)return a;
    a%=pp;
    if(a<0)a+=pp;
    return a;
}
ll mo(ll a){
    if(a>=0&&a<mod)return a;
    a%=mod;
    if(a<0)a+=mod;
    return a;
}
ll powmod(ll a,ll b,ll pp){
    ll ans=1;
    for(;b;b>>=1,a=mo(a*a,pp)){
        if(b&1)ans=mo(ans*a,pp);
    }
    return ans;
}
ll powmod(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1,a=mo(a*a)){
        if(b&1)ans=mo(ans*a);
    }
    return ans;
}
 
ll C(int n,int m){
	if(n<m)return 0;
	if(m==n||m==0)return 1;
	return b[n]*invf[n-m]%mod*invf[m]%mod;
}
void init(){
    b[0]=1;
    for(int i=1;i<maxn;i++)b[i]=b[i-1]*i%mod;
    inv[1]=1;//逆元
    for(int i=2;i<maxn;i++)inv[i]=((mod-mod/i)*inv[mod%i])%mod;
	invf[0]=1;//累乘逆元
    for(int i=1;i<maxn;i++)invf[i]=(invf[i-1]*inv[i])%mod;
    f[0]=0;f[1]=1;f[2]=1;
    for(int i=3;i<maxn;i++)f[i]=(f[i-1]+f[i-2])%(mod-1);
     
}
ll inv1(ll b){
	return powmod(b,mod-2,mod);
}
ll inv2(ll a){
	if(a==1)return 1;
	return inv2(mod%a)*inv2(mod-mod/a)%mod;
}
 
int main(){
	int t;
	scanf("%d",&t);
	init();
	while(t--){
		int n,m,k;
		scanf("%d%d%d",&n,&m,&k);
		ll tot=C(k+m-1,m-1)%mod;
		if(k<=(n-1)){
			printf("%lld\n",tot);
		}
		else{
			for(int i=1;i<=m;i+=2){
				if(k-i*n<0)break;
				tot=(tot-C(m,i)%mod*C(k-i*n+m-1,m-1)%mod+mod*mod)%mod;
				if(k-(i+1)*n<0)break;
				if((i+1)>m)break;
				tot=(tot+C(m,(i+1))%mod*C(k-(i+1)*n+m-1,m-1)%mod)%mod;
			}
			printf("%lld\n",tot);
		}
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/yz467796454/article/details/81709195