Codeforces451E Devu and Flowers
阿新 • • 發佈:2019-04-04
clas for href org bits 時間復雜度 傳送門 pac math
題目傳送門
Description
\(n\)種花\((n\leq20)\),每種花不超過\(f_i\)朵,問總數為\(s\)的方案數
Solution
容斥+組合數學
因為\(n\)很小,考慮容斥,即無任何限制的方案數\(-\)至少一種不滿足的方案數\(+\)至少兩種不滿足的方案數。。。
如何求無任何限制的方案數?問題可以轉化為\(x_1+x_2+\dots+x_n=s\)的非負解數,用組合數學的隔板法解決,方案數為\(C^{n-1}_{s+n-1}\)。
如何求至少一種不滿足的方案數?答案為\(\sum_{i=1}^{n}C_{s-f_i-1+n-1}^{n-1}\)。因為至少要讓一種花的數量在限制外。
那麽解法呼之欲出了。每到一種花遞歸求解該種強制不選或隨意的方案數,強制不選就使\(s-=(f_i+1)\),隨意就將\(s\)繼續遞歸,同時維護容斥系數即可。
時間復雜度\(O(n2^n)\)
細節見代碼:
#include<bits/stdc++.h> #define int long long #define rep(i, a, b) for (register int i=(a); i<=(b); ++i) #define per(i, a, b) for (register int i=(a); i>=(b); --i) using namespace std; const int N=25, P=1e9+7; void add(int &a, int b){a=a+b>=P?a+b-P:a+b;} int mul(int a, int b){return a*b-a*b/P*P;} int f[N], inv[N], n, s, sum; inline int read() { int x=0,f=1;char ch=getchar(); for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1; for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0'; return x*f; } int C(int n, int m) { if (n<m) return 0; int res=1; rep(i, 1, m) res=mul(res, mul((n-i+1)%P, inv[i])); return res; } int dfs(int i, int s, int sign) { if (s<0) return 0; if (i==n+1) return sign*C(s+n-1, n-1); int ans=dfs(i+1, s, sign); add(ans, dfs(i+1, s-f[i]-1, 0-sign)); return ans<0?ans+P:ans; } signed main() { n=read(); s=read(); rep(i, 1, n) f[i]=read(), sum+=f[i]; inv[1]=1; rep(i, 2, n) inv[i]=mul(inv[P%i], P-P/i); printf("%d\n", sum<s?0:dfs(1, s, 1)); return 0; }
Codeforces451E Devu and Flowers