北京集训test8-P3专攻:生日礼物(NTT+组合数取模+第二斯特林数)
题目:
Description
今天是Jane的生日。Alice和Bob都有一些糖果,于是这两个人就去买一些白色的盒子去包装这些糖果作为Jane的生日礼物。他们将随机地把这些盒子分成两堆,一堆给Alice,一堆给Bob(每堆至少有一个盒子)。
我们知道Alice有 N1 个不同的糖果,Bob有 N2 个相同的糖果(由于Bob很懒,所以他直接买了相同的糖果),然后Alice买的糖果和Bob买的糖果是完全不一样的。他们两人各自把糖果放进盒子里,并且任意一个盒子都不会是空的。Alice和Bob各自有各自包装糖果的规则:
Alice很有个性,她会根据盒子的数量来决定包装糖果的方法。记Alice拥有的盒子数量为 k 。若 k 是个质数,则她会随机地包装糖果(每个糖果都有可能进入任意一个盒子里)。若 k 不是质数,她会往其中的 k−1 个盒子里分别随机放入1个糖果,将剩下的糖果全部放入剩下那个盒子里。
Bob有M种颜料(这M种颜料中没有白色),他将随机地给盒子上色,使得每个盒子都有上色且颜色不一样。然后Bob会随机地包装糖果(每个糖果都可能进入任意一个盒子里)。
问题来了,Jane会收到多少种礼物?
Input
第一行为一个整数T,表示测试数据组数。
对于每组测试数据,第一行为四个整数 N1,N2,M,Q ,分别表示Alice的糖果数目、Bob的糖果数目、Bob的颜色数目、询问个数。
接下来Q行,每行一个整数N,表示Alice和Bob购买的盒子的总数 (2≤N≤M) 。
Output
Sample Input
1
4 3 3 2
2
3
Sample Output
3
27
HINT
【样例解释】
Alice的糖果为 A,B,C,D,Bob的糖果为 a,a,a ,Bob的颜色为 C1, C2, C3。盒子初始的颜色为W。
对于n = 2,Jane可以收到3种礼物:
W{A,B,C,D},C1{a,a,a}
W{A,B,C,D},C2{a,a,a}
W{A,B,C,D},C3{a,a,a}
对于n = 3,Jane可以收到27种礼物:
W{A},W{B,C,D},C1{a,a,a}
W{A},W{B,C,D},C2{a,a,a}
W{A},W{B,C,D},C3{a,a,a}
W{B},W{A,C,D},C1{a,a,a}
W{B},W{A,C,D},C2{a,a,a}
W{B},W{A,C,D},C3{a,a,a}
W{C},W{A,B,D},C1{a,a,a}
W{C},W{A,B,D},C2{a,a,a}
W{C},W{A,B,D},C3{a,a,a}
W{D},W{A,B,C},C1{a,a,a}
W{D},W{A,B,C},C2{a,a,a}
W{D},W{A,B,C},C3{a,a,a}
W{A,B},W{C,D},C1{a,a,a}
W{A,B},W{C,D},C2{a,a,a}
W{A,B},W{C,D},C3{a,a,a}
W{A,C},W{B,D},C1{a,a,a}
W{A,C},W{B,D},C2{a,a,a}
W{A,C},W{B,D},C3{a,a,a}
W{A,D},W{B,C},C1{a,a,a}
W{A,D},W{B,C},C2{a,a,a}
W{A,D},W{B,C},C3{a,a,a}
W{A,B,C,D},C1{a},C2{a,a}
W{A,B,C,D},C1{a},C3{a,a}
W{A,B,C,D},C2{a},C1{a,a}
W{A,B,C,D},C2{a},C3{a,a}
W{A,B,C,D},C3{a},C1{a,a}
W{A,B,C,D},C3{a},C2{a,a}
【数据范围与约定】
对于10%的数据: 1≤N1,N2,M,Q≤10
对于50%的数据: 1≤N1,N2,M,Q≤1000
对于所有数据: 1≤N1,N2,M,Q≤105,T≤5
题解:
考点:
1.NTT
2.逆元求组合数取模,参照(感谢神犇):http://blog.csdn.net/arrowlll/article/details/52629448
3.第二类斯特林数
心得:
是道好题····涉及了数论方面3个重要的知识。
代码:
#include<bits/stdc++.h> #define LL long long using namespace std; const int N = 600009; const int MOD = 786433; const int RT = 13; int g[N],f[N],POW[N],REV[N],pos[N]; int n1,n2,m,q,vis[N],a[N],b[N]; inline int read() { char c=getchar(); int ret=0,f=1; while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();} while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();} return ret*f; } inline int Pow(int w, int t) { int ret = 1; for (;t;t>>=1,w=(LL)w*w%MOD) if(t&1)ret=(LL)ret*w%MOD; return ret; } inline int C(int a, int b) { if (a > b) return 0; return ((LL)POW[b] * REV[a] % MOD) * REV[b-a] % MOD; } inline void prework() { for (int i=2;i<N;i++) { for (int j=i*2;j<N;j+=i) { vis[j] = 1; } } vis[1] = 1; POW[0] = REV[0] = 1; for (int i=1;i<N;i++) POW[i] = (LL)POW[i-1] * i % MOD; REV[N-1] = Pow(POW[N-1], MOD-2); for (int i=N-2;i;i--) REV[i] = REV[i+1] * (i+1ll) % MOD; } inline void ntt(int *a, int len, int rev = 0) { for (int i=0;i<len;i++) if (pos[i]<i) swap(a[i], a[pos[i]]); for (int l=2;l<=len;l<<=1) { int wn = Pow(RT, MOD / l); if (rev) wn = Pow(wn, MOD-2); for (int i=0,w=1,tmp;i<len;i+=l,w=1) { for (int j=0;j<(l>>1);j++,w=(LL)w*wn%MOD) { tmp = (LL)w * a[i+j+(l>>1)] % MOD; a[i+j+(l>>1)] = (a[i+j] - tmp) % MOD; a[i+j] = (a[i+j] + tmp) % MOD; } } } if (rev) for (int i=1,Rev=Pow(len,MOD-2);i<=len;i++) a[i] = ((LL)a[i] * Rev % MOD + MOD) % MOD; } inline void solve(int l, int *a, int *b) { int t = -1, len = 1; while (len < (l+1)) len <<= 1, t++; for (int i=0;i<len;i++) { pos[i] = pos[i>>1]>>1; if (i&1) pos[i] |= 1<<t; } ntt(a, len); ntt(b, len); for (int i=0;i<len;i++) a[i] = (LL)a[i] * b[i] % MOD; ntt(a, len, 1); } inline void update() { memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for (int i=1;i<=n2;i++) g[i] = (LL)C(i-1, n2-1) * C(i, m) % MOD; for (int i=0;i<=n1;i++) { a[i] = (i&1)? MOD-REV[i]: REV[i]; b[i] = (LL)Pow(i, n1) * REV[i] % MOD; } solve(n1 << 1, a, b); for (int i=1;i<=n1;i++) { if (vis[i]) f[i] = i==n1? 1: C(i-1, n1); else f[i] = a[i]; } } int main() { //freopen("11input.in","r",stdin); prework(); for (int T=read();T;T--) { n1 = read(); n2 = read(); m = read(); update(); solve(n1 + n2, f, g); for (int q=read();q;q--) printf("%d\n",(f[read()]+MOD)%MOD); } return 0;


浙公网安备 33010602011771号