2018 Multi-University Training Contest 8 1001 Character Encoding【容斥】
阿新 • • 發佈:2018-12-24
題意:每個數字的取值範圍為0到n-1,共有m個數字,求總和為k的方案數。
因為k的上限為1e5,那麼我們不妨把k看做k個1,然後通過m-1個隔板來分割出m個數字。但是這麼做會有一個問題,那就是數字可能為0。那麼不妨將數字的取值範圍改成1-n,m個數所以k要相應的變成k+m,那麼就可以使用隔板法了。
先無限制的求一下總數:
如果我們現在拿出來n個1,將剩下的數分割成m個數,那麼把這n個1放到任何位置上,都是至少有一個數字超出限制的。
也就是:
如此反覆直到不合法結束,到x結束也就是 到無法滿足至少x個數超過限制時結束。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
#define LL long long
const LL N = 3e5 + 10;
const LL MAXN = 3e5;
const LL mod = 998244353 ;
LL fac[N];
LL inv[N];
LL qkm(LL base,LL mi)
{
LL ans=1;
while(mi){
if(mi&1) ans=ans*base%mod;
base=base*base%mod;
mi>>=1;
}
return ans;
}
LL C(LL n,LL m)
{
if(m>n) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
fac[0 ]=fac[1]=1;
for(LL i=2;i<=MAXN;i++)fac[i]=fac[i-1]*i%mod;
inv[MAXN]=qkm(fac[MAXN],mod-2);
for(LL i=MAXN-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
LL T;
cin>>T;
while(T--){
LL n,m,k;
cin>>n>>m>>k;
LL ans=C(k+m-1,m-1);
LL p=1;
LL di = k+m-1-n;
LL num=1;
while(di>=m-1){
if(p){
ans=ans-C(m,num)*C(di,m-1)%mod+mod;
ans%=mod;
}else{
ans=ans+C(m,num)*C(di,m-1)%mod;
ans%=mod;
}
p=p^1;
num++;
di-=n;
}
cout<<ans<<endl;
}
return 0;
}