[loj3653]抽奖机

用$n$位三进制数描述状态,记$F_{S}=\sum_{i=1}^{m}[a_{i}=x,b_{i}=y]$(其中$x$和$y$分别为$S$在三进制下1和2的个数)

定义$x\oplus y$为$x$和$y$在三进制下执行不进位加法的结果$,\odot $为$\oplus$对应的卷积,问题即求$F\odot F...\odot F$(共$k$个)

关于$\odot$,每一位可以理解为对每一位做一个模3的加法卷积,以三次单位根$\omega$做NTT即可

具体的,构造变换$f(A)_{S}=\sum_{T}\omega^{\sum_{i=0}^{n-1}trans(S_{i},T_{i})}A_{T}$(其中$S_{i}$和$T_{i}$分别指两者三进制下第$i$位)

关于$trans$,即NTT的系数中$\omega$的幂次,具体形式为$\left(\begin{array}{ll}0&0&0\\0&1&2\\0&2&1\end{array}\right)$

通过变换$f$,有$f(A\odot B)_{S}=f(A)_{S}\times f(B)_{S}$和$f^{-1}(A)_{S}=\frac{f(A)_{S\oplus S}}{3^{n}}$,具体均可代入证明

注意到$F_{S}$仅取决于$S$在三进制下1和2的个数,记$F_{a,b}$表示含有$a$个1和$b$个2的$F_{S}$的值,以此即可表示$F$

将此时$F_{a,b}$对$f(F)_{p,q}$的贡献系数构建二元生成函数$H_{a,b}(x,y)$​,看作一个二维背包,即有
$$
H_{a,b}(x,y)=\frac{{n\choose a,b}}{n\choose x,y}(1+\omega x+\omega^{2}y)^{a}(1+\omega^{2}x+\omega y)^{b}(1+x+y)^{n-a-b}
$$
提出常数项后,记其为$H'_{a,b}$,考虑其递推式,即
$$
(1+x+y)H'_{a,b}(x,y)=(1+\omega^{2}x+\omega y)H'_{a,b-1}(x,y)
$$
(对于$b=0$的情况,可以类似地对$a$递推,注意处理边界)

由于内存限制,上述递推需要滚动实现,那么在递推过程中实现变换$f$即可

最终,总复杂度为$o(n^{4}+n^{2}\log k)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 125
 4 #define mod 1000000009
 5 #define w 115381398
 6 #define w2 884618610
 7 #define ll long long
 8 int n,m,x,y,C[N][N],h[N][N],g[N][N],f[N][N],F0[N][N],F[N][N];
 9 ll k;
10 int qpow(int n,ll m){
11     int s=n,ans=1;
12     while (m){
13         if (m&1)ans=(ll)ans*s%mod;
14         s=(ll)s*s%mod,m>>=1;
15     }
16     return ans;
17 }
18 void turn_a(){
19     memset(h,0,sizeof(h));
20     for(int i=0;i<=n;i++)
21         for(int j=0;j<=n-i;j++){
22             h[i][j]=g[i][j];
23             if (i)h[i][j]=(h[i][j]+(ll)w*g[i-1][j]-h[i-1][j]+mod)%mod;
24             if (j)h[i][j]=(h[i][j]+(ll)w2*g[i][j-1]-h[i][j-1]+mod)%mod;
25         }
26     memcpy(g,h,sizeof(g));
27 }
28 void turn_b(){
29     memset(h,0,sizeof(h));
30     for(int i=0;i<=n;i++)
31         for(int j=0;j<=n-i;j++){
32             h[i][j]=f[i][j];
33             if (i)h[i][j]=(h[i][j]+(ll)w2*f[i-1][j]-h[i-1][j]+mod)%mod;
34             if (j)h[i][j]=(h[i][j]+(ll)w*f[i][j-1]-h[i][j-1]+mod)%mod;
35         }
36     memcpy(f,h,sizeof(f));
37 }
38 void FWT(int p=0){
39     memset(g,0,sizeof(g));
40     memset(F0,0,sizeof(F0));
41     for(int i=0;i<=n;i++)
42         for(int j=0;j<=n-i;j++){
43             g[i][j]=(ll)C[n][i]*C[n-i][j]%mod;
44             F[i][j]=(ll)F[i][j]*g[i][j]%mod;
45         }
46     for(int i=0;i<=n;i++){
47         memcpy(f,g,sizeof(f));
48         for(int j=0;j<=n-i;j++){
49             for(int x=0;x<=n;x++)
50                 for(int y=0;y<=n-x;y++)F0[x][y]=(F0[x][y]+(ll)F[i][j]*f[x][y])%mod;
51             turn_b();
52         }
53         turn_a();
54     }
55     for(int i=0;i<=n;i++)
56         for(int j=0;j<=n-i;j++){
57             int s=(ll)C[n][i]*C[n-i][j]%mod;
58             F[i][j]=(ll)F0[i][j]*qpow(s,mod-2)%mod;
59         }
60     if (p){
61         int s=qpow(qpow(3,n),mod-2);
62         for(int i=0;i<=n;i++)
63             for(int j=0;(j<i)&&(j<=n-i);j++)swap(F[i][j],F[j][i]);
64         for(int i=0;i<=n;i++)
65             for(int j=0;j<=n-i;j++)F[i][j]=(ll)F[i][j]*s%mod;
66     }
67 }
68 int main(){
69     for(int i=0;i<N;i++){
70         C[i][0]=C[i][i]=1;
71         for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
72     }
73     scanf("%d%d%lld",&n,&m,&k);
74     for(int i=1;i<=m;i++){
75         scanf("%d%d",&x,&y);
76         F[x][y]++;
77     }
78     FWT();
79     for(int i=0;i<=n;i++)
80         for(int j=0;j<=n-i;j++)F[i][j]=qpow(F[i][j],k);
81     FWT(1);
82     for(int i=0;i<=n;i++)
83         for(int j=0;j<=n-i;j++)F[i][j]=(ll)F[i][j]*C[n][i]%mod*C[n-i][j]%mod;
84     for(int i=0;i<=n;i++){
85         for(int j=0;j<=n-i;j++)printf("%d ",F[i][j]);
86         printf("\n");
87     }
88     return 0;
89 } 
View Code

 

posted @ 2022-02-20 19:10  PYWBKTDA  阅读(90)  评论(0编辑  收藏  举报