链接:https://www.nowcoder.com/acm/contest/133/D
来源:牛客网
题目描述
Applese打开了m个QQ群,向群友们发出了组队的邀请。作为网红选手,Applese得到了n位选手的反馈,每位选手只会在一个群给Applese反馈
现在,Applese要挑选其中的k名选手组队比赛,为了维持和各个群的良好关系,每个群中都应有至少一名选手成为Applese的队友(数据保证每个群都有选手给Applese反馈)
Applese想知道,他有多少种挑选队友的方案
现在,Applese要挑选其中的k名选手组队比赛,为了维持和各个群的良好关系,每个群中都应有至少一名选手成为Applese的队友(数据保证每个群都有选手给Applese反馈)
Applese想知道,他有多少种挑选队友的方案
输入描述:
输入包括两行
第一行包括三个数n, m, k,表示共有n位选手,m个群,需要有k名选手被选择
第二行包括m个数,第i个数表示第i个群有si个选手
n ≤ 100000, m ≤ k ≤ n
输出描述:
输出包括一行
第一行输出方案数
由于输出可能比较大,你只需要输出在模998244353意义下的答案
示例1
输入
5 3 4 1 2 2
输出
4
思路分析: dp[i][j] 表示前 i 个QQ 群中选了 j 个人的方案数,并且保证每个群中至少选 1 人
dp[i][j] += dp[i-1][j-h]*C(x, h) , 其实本质意思就是第一个群选 1个, 2个,... n 个所对应的方案 * 第二个群选 1个, 2个, ... n个,这不就是个多项式的乘法吗,又因为其带模数,所以一个NTT,就可以了
代码示例 :
#include <bits/stdc++.h> using namespace std; #define ll long long const ll maxn = 1e5+5; const ll mod = 998244353; ll n, m, k; vector<ll>ve[maxn]; ll pp[maxn], inv[maxn]; ll qw(ll a, ll b){ ll res = 1; a %= mod; while(b){ if (b&1) res = res*a%mod; a = a*a%mod; b >>= 1; } return res; } ll C(ll n, ll m){ ll ans = pp[n]*inv[m]%mod*inv[n-m]%mod; return ans; } ll rev (ll x, ll len){ ll ret = 0; for(ll i = 0; (1<<i)<len; i++){ ret <<= 1; if ((1<<i)&x) ret |= 1; } return ret; } void NTT(vector<ll>& p, ll len, ll DFT){ for(ll i = 0; i < len; i++){ ll x= rev(i, len); if (i < x) swap(p[i], p[x]); } for(ll i = 1; i < len; i <<= 1){ ll wn = qw(3, (mod-1)/(2*i)); if (DFT == -1) wn = qw(wn, mod-2); for(ll j = 0; j < len; j += i*2){ ll w = 1; for(ll k = 0; k < i; k++){ ll x = p[j+k]; ll y = w*p[j+k+i]%mod; p[j+k]=(x+y)%mod; p[j+k+i]=(x-y+mod)%mod; w = w*wn%mod; } } } if (DFT == -1) for(ll i = 0, x = qw(len, mod-2); i < len; i++) p[i]=p[i]*x%mod; } void mul(vector<ll>& a, vector<ll> b){ ll n = a.size(), m = b.size(); ll len = 1; while(len < (n+m)) len <<= 1; a.resize(len); b.resize(len); NTT(a, len, 1); NTT(b, len, 1); for(ll i = 0; i < len; i++) a[i] = a[i]*b[i]%mod; NTT(a, len, -1); a.resize(n+m); } queue<ll>que; int main() { ll x; pp[0] = 1; for(ll i = 1; i <= 100000; i++) pp[i]=pp[i-1]*i%mod; for(ll i = 0; i <= 100000; i++) inv[i]=qw(pp[i],mod-2); cin >> n >> m >> k; for(ll i = 1; i <= m; i++){ scanf("%lld", &x); ve[i].resize(x); for(ll j = 0; j < x; j++) ve[i][j] = C(x, j+1); // 下标从0开始 que.push(i); } while(que.size() > 1){ ll u = que.front(); que.pop(); ll v = que.front(); que.pop(); mul(ve[u], ve[v]); que.push(u); } printf("%lld ", ve[que.front()][k-m]); //for(ll i = 0; i <= ve[que.front()].size(); i++) printf("++%lld %lld ",i, ve[que.front()][i]); return 0; }