Character Encoding(hdu 6397 容斥)
阿新 • • 發佈:2018-11-25
題目:
題意:
x1+x2+x3+...+xm=k,其中0<=xi<=n-1,已知n,m,k,求所有可能的情況數。
思路:
這是一個方程整數解的經典問題,可用容斥定理求解。
若xi>=0,無上限,那麼總的情況數 = C(m+k-1,m-1) 。
(此公式可用隔板法推得:總共有k個1,要把它分成m段,需要m-1個隔板,那就是在總共k+m-1個東西中隨機選m-1個當做隔板,方案數為C(m+k-1,m-1) 。)
現在統計的所有情況中有2類數:
第一類:0<=xi<=n-1,即滿足條件的數。
第二類:xi>=n,即違反條件的數,將其減去n之後,它就滿足xi>=0,就可以使用上面那個式子進行計算了。
設有p個不合法的數:
p=1時,總的情況數就為C(m+k-1-n*1,m-1)*C(m,1),其意義為找出有一個違法的數的情況,並把這個數隨機放到1-m的位置。
p=2時,總的情況數就為C(m+k-1-n*2,m-1)*C(m,1),表示有2個數同時違法,並把這2個數隨機放到1-m的位置。這種情況其實就是符合p=1時的兩種可能情況的交集,這就是容斥的意義。
同理,p=3是就是符合p=1時的3種可能情況的交集。
...
根據容斥的性質,奇數個交集乘以容斥係數-1,偶數個交集乘以容斥係數1 。
因此,總的公式就為 。
程式碼:
#include <iostream> #include <string> #include <cstdio> #include <cstring> #include <cmath> #include <set> #include <vector> #include <cstdlib> #include <algorithm> using namespace std; typedef long long ll; const int MAX = 1e6+10; const ll mod=998244353; ll F[MAX], Finv[MAX], inv[MAX];//F是階乘,Finv是逆元的階乘 void init(){ inv[1] = 1; for(int i = 2; i < MAX; i ++){ inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod; } F[0] = Finv[0] = 1; for(int i = 1; i < MAX; i ++){ F[i] = F[i-1] * 1ll * i % mod; Finv[i] = Finv[i-1] * 1ll * inv[i] % mod; } } ll comb(ll n, ll m){//comb(n, m)就是C(n, m) if(m < 0 || m > n) return 0; return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod; } int main() { int T; scanf("%d",&T); init(); while(T--) { ll n,m,k; scanf("%lld%lld%lld",&n,&m,&k); ll ans=0; for(int i=0;i<=min(k/n,m);i++){ if(i%2==0) ans=(ans+comb(m+k-1-i*n,m-1)*comb(m,i)%mod+mod)%mod; else ans=(ans-comb(m+k-1-i*n,m-1)*comb(m,i)%mod+mod)%mod; } printf("%lld\n",ans); } return 0; }