1. 程式人生 > >Codeforces451E Devu and Flowers

Codeforces451E Devu and Flowers

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