Wan fl 20D
题意:M个Q群,每个群有si个人,每个群至少选一个,选K个人的方案数
思路:每个群挑选的生成函数为,答案就是m个G(i)的生成函数之积后
的的系数 生成函数之积NTT,多个相乘,加个分治,
此题需要用邻接表。。原来的板子不适用了
#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
const int N = 401000;//大概4倍
inline int Add(int x, int y) { x += y; if(x >= MOD) x -= MOD; return x; }
inline int Dec(int x, int y) { x -= y; if(x < 0) x += MOD; return x; }
inline int Mul(int x, int y) { return 1LL * x * y % MOD; }
inline int Kissme(int x, int y) {
int c = 1;
while(y) {
if(y & 1) c = Mul(c, x);
x = Mul(x, x);
y >>= 1;
}
return c;
}
namespace FFT { //固定板子
int L, l, rev[N << 1];
void Pre(int n) {
for(l = 0; (1 << l) < n; l++); L = 1 << l;
for(int i = 0; i < L; i++) rev[i] = rev[i >> 1] >> 1 | (i & 1) << (l - 1);
}
void Dft(int *a) {
for(int i = 0; i < L; i++)
if(i > rev[i]) swap(a[i], a[rev[i]]);
for(int i = 1; i < L; i <<= 1)
{
int wn = Kissme(3, (MOD - 1) / (i << 1));//原根修改处
for(int j = 0; j < L; j += i << 1)
for(int w = 1, k = 0; k < i; k++, w = Mul(w, wn))
{
int u = a[j + k], v = Mul(w, a[i + j + k]);
a[j + k] = Add(u, v);
a[i + j + k] = Dec(u, v);
}
}
}
void Idft(int *a) {
reverse(a + 1, a + L); int inv = Kissme(L, MOD - 2);
Dft(a);
for(int i = 0; i < L; i++)
a[i] = Mul(a[i], inv);
}
}
vector<int> Mul(vector<int> a, vector<int> b) {
using namespace FFT;
vector<int> c;
int n = a.size() + b.size() - 1;
if(1LL * a.size() * b.size() <= (a.size() + b.size()) * 20LL) {
c.resize(n);
for(int i = 0; i < a.size(); i++)
for(int j = 0; j < b.size(); j++)
c[i + j] = Add(c[i + j], Mul(a[i], b[j]));
return c;
}
Pre(n);//固定操作 更新L
c.resize(L); a.resize(L); b.resize(L);
Dft(&a[0]); Dft(&b[0]);
for(int i = 0; i < L; i++)
c[i] = Mul(a[i], b[i]);
Idft(&c[0]);
c.resize(n);
return c;
}
int fac[N], inv[N], fa[N], siz[N], n, K, m;
vector<vector<int> > All;
vector<int> T[N << 2];
void Init(void) {//预处理阶乘
fac[0] = 1; int lim = 100001;
for(int i = 1; i <= lim; i++) fac[i] = Mul(fac[i - 1], i);
inv[lim] = Kissme(fac[lim], MOD - 2);
for(int i = lim - 1; i >= 0; i--) inv[i] = Mul(inv[i + 1], i + 1);//乘
}
int C(int x, int y) {
if(y > x) return 0;
return Mul(fac[x], Mul(inv[y], inv[x - y]));
}
void Solve(int o, int l, int r) {//分治 多个多项式相乘
if(l == r) return(void)(T[o] = All[l]);
int mid = l + r >> 1;
Solve(o << 1, l, mid);
Solve(o << 1 | 1, mid + 1, r);
T[o] = Mul(T[o << 1], T[o << 1 | 1]);
}
int main(void) {
Init();
scanf("%d%d%d", &n, &m, &K);
All.clear();
for(int i = 1; i <= m; i++)
{
vector<int> x;//第i个多项式的系数
x.push_back(0);
int y;
scanf("%d", &y);
for(int j = 1; j <= y; j++)
x.push_back(C(y, j));
All.push_back(x);//ALL就是所有多项式的系数集合
}
Solve(1, 0, All.size() - 1);//一共all.size个多项式
printf("%d\n", T[1][K]);//x^K的系数
return 0;
}