北京集训test8-P3专攻:生日礼物(NTT+组合数取模+第二斯特林数)

题目:

Description

      今天是Jane的生日。Alice和Bob都有一些糖果,于是这两个人就去买一些白色的盒子去包装这些糖果作为Jane的生日礼物。他们将随机地把这些盒子分成两堆,一堆给Alice,一堆给Bob(每堆至少有一个盒子)。

      我们知道Alice有 N1 个不同的糖果,Bob有 N2 个相同的糖果(由于Bob很懒,所以他直接买了相同的糖果),然后Alice买的糖果和Bob买的糖果是完全不一样的。他们两人各自把糖果放进盒子里,并且任意一个盒子都不会是空的。Alice和Bob各自有各自包装糖果的规则:

      Alice很有个性,她会根据盒子的数量来决定包装糖果的方法。记Alice拥有的盒子数量为 k 。若 k 是个质数,则她会随机地包装糖果(每个糖果都有可能进入任意一个盒子里)。若 k 不是质数,她会往其中的 k1 个盒子里分别随机放入1个糖果,将剩下的糖果全部放入剩下那个盒子里。

      Bob有M种颜料(这M种颜料中没有白色),他将随机地给盒子上色,使得每个盒子都有上色且颜色不一样。然后Bob会随机地包装糖果(每个糖果都可能进入任意一个盒子里)。

      问题来了,Jane会收到多少种礼物?

Input

      第一行为一个整数T,表示测试数据组数。

      对于每组测试数据,第一行为四个整数 N1,N2,M,Q ,分别表示Alice的糖果数目、Bob的糖果数目、Bob的颜色数目、询问个数。

      接下来Q行,每行一个整数N,表示Alice和Bob购买的盒子的总数 (2NM) 。

Output

      对于每组测试数据,输出Q行,每行一个整数表示Jane可能收到的礼物的种数。由于答案可能非常大,请将答案对786433取模后输出。

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%的数据: 1N1,N2,M,Q10

      对于50%的数据: 1N1,N2,M,Q1000

      对于所有数据: 1N1,N2,M,Q105,T5


题解:

 

考点:

  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;

 

  

 

posted @ 2017-03-15 19:14  AseanA  阅读(157)  评论(0)    收藏  举报