[uoj272]石家庄的工人阶级队伍比较坚强

假设$x,y\in \{0,1,2\}$,则$x$能赢$y$(根据题中定义)当且仅当$x-y\equiv 1(mod\ 3)$

定义$\ominus$为两数3进制下不退位的减法,$S_{x}$表示$x$在3进制下1的个数,则$u=W(x,y)=S_{x\ominus y}$,类似地,有$v=W(y,x)=S_{y\ominus x}$

记$B_{x,y}=b_{S_{x\ominus y},S_{y\ominus x}}$,令$k=x\ominus y$,根据$\ominus$的性质,有$k\ominus 0=x\ominus y$以及$0\ominus k=y\ominus x$,代入后就可以得到$B_{x,y}=b_{S_{k\ominus 0},S_{0\ominus k}}=B_{k,0}$,再记$g_{k}=B_{k,0}$,可以预处理出来

原题也就是$f_{i,x}=\sum_{y=0}^{3^{m}-1}g_{x\ominus y}f_{i-1,y}$,再令$\oplus$为3进制下按位加法,有$(x\ominus y)\oplus y=x$,也就是一个$\oplus$的卷积,记这个卷积为$\otimes$运算,有$f_{i}=g\otimes f_{i-1}$

根据卷积的结合律,有$f_{t}=g^{t}\otimes f_{0}$(其中$g^{t}$也是上面的$\otimes$),也就是要快速计算$\otimes$运算

我们直接来考虑原问题的一个拓展,即令$\oplus$为$B$进制下不进位加法,$\otimes$为$\oplus$卷积($B$是一个较小的数),如何对两个序列快速计算$\otimes$这个运算

为了方便起见,不妨假设序列长度$n=B^{k}$,不足可以补0

对于两个序列$a_{i}$和$b_{i}$,考虑构造一个$n\times n$的矩阵$A_{i,j}$(将序列看作一个$1\times n$的矩阵),令$a'=aA$,$b'=bA$,再令$c'=a'*b'$(这里的*指对应位置相乘),最后$c=c'A^{-1}$

$\forall n=B^{k}(k\ge 1)$,若矩阵$A$满足以下两个条件,则最终有$c=a\otimes b$:

1.其左上角$B\times B$的矩阵在$n=B$时满足$c=a\otimes b$

2.$A_{i,j}=A_{\lfloor\frac{i}{B}\rfloor,\lfloor\frac{j}{B}\rfloor}A_{i\ mod\ B,j\ mod\ B}$,且$A^{-1}$具有同样性质

证明如下——

注意到当$n=B$时,左上角$B\times B$的矩阵即为$A$本身,那么由条件1可知其正确

归纳$n=B^{k}(k\ge 1)$时正确,考虑$n=B^{k+1}$时正确性:

对于每一个$0\le i<B^{k+1}$,都可以被表示为$i_{0}B+i_{1}$(其中$0\le i_{0}<B^{k}$,$0\le i_{1}<B$)

对于$a_{i}$和$b_{i}$,代入式子即有
$$
c_{i}=\sum_{j=0}^{B^{k+1}-1}c'_{j}A^{-1}_{j,i}=\sum_{j_{1}=0}^{B-1}\sum_{j_{0}=0}^{B^{k}-1}c'_{j_{0}B+j_{1}}A^{-1}_{j_{0}B+j_{1},i_{0}B+i_{1}}=\sum_{j_{1}=0}^{B-1}A^{-1}_{j_{1},i_{1}}\sum_{j_{0}=0}^{B^{k}-1}c'_{j_{0}B+j_{1}}A^{-1}_{j_{0},i_{0}}
$$
考虑$c'_{i}$,同样可以代入得到
$$
c'_{i}=a'_{i}b'_{i}=(\sum_{j_{1}=0}^{B-1}A_{j_{1},i_{1}}\sum_{j_{0}=0}^{B^{k}-1}a_{j_{0}B+j_{1}}A_{j_{0},i_{0}})(\sum_{j_{1}=0}^{B-1}A_{j_{1},i_{1}}\sum_{j_{0}=0}^{B^{k}-1}b_{j_{0}B+j_{1}}A_{j_{0},i_{0}})
$$
(关于$a'_{i}$和$b'_{i}$用$a_{i}$和$b_{i}$表达,与$c_{i}$用$c'_{i}$表达相同,将$A^{-1}$改为$A$即可)

对$a_{i}$和$b_{i}$分别构造出$B$个序列,即$d_{j_{0},i}=a_{iB+j_{0}}$以及$e_{j_{0},i}=b_{iB+j_{0}}$,考虑$d_{x}$和$e_{y}$分别作为$a_{i}$和$b_{i}$通过前面的方式计算,可以算出$c'$,记作$f'_{x,y}$,即有
$$
f'_{x,y,i}=(\sum_{j=0}^{B^{k}-1}d_{x,j}A_{j,i})(\sum_{j=0}^{B^{k}-1}e_{y,j}A_{j,i})=(\sum_{j=0}^{B^{k}-1}a_{jB+x}A_{j,i})(\sum_{j=0}^{B^{k}-1}b_{jB+y}A_{j,i})
$$
可以发现这个式子与上面的$c'_{i}$有关,具体来说即
$$
c'_{i}=\sum_{x=0}^{B-1}A_{x,i_{1}}\sum_{y=0}^{B-1}A_{y,i_{1}}f'_{x,y,i_{0}}
$$
整体将$c'_{i}$的式子代入$c_{i}$中,也就得到了
$$
c_{i}=\sum_{j_{1}=0}^{B-1}A^{-1}_{j_{1},i_{1}}\sum_{j_{0}=0}^{B^{k}-1}A^{-1}_{j_{0},i_{0}}\sum_{x=0}^{B-1}A_{x,j_{1}}\sum_{y=0}^{B-1}A_{y,j_{1}}f'_{x,y,j_{0}}=\sum_{j_{1}=0}^{B-1}A^{-1}_{j_{1},i_{1}}\sum_{x=0}^{B-1}A_{x,j_{1}}\sum_{y=0}^{B-1}A_{y,j_{1}}\sum_{j_{0}=0}^{B^{k}-1}A^{-1}_{j_{0},i_{0}}f'_{x,y,j_{0}}
$$
显然最后一个式子也就是$f'_{x,y}A^{-1}$,记作$f_{x,y}$,根据归纳有$f_{x,y}=d_{x}\otimes e_{y}$,联系其定义即
$$
f_{x,y,i}=\sum_{0\le p_{0},q_{0}<B^{k},p_{0}\oplus q_{0}=i}d_{x,p_{0}}e_{y,q_{0}}
$$
再次代入$c_{i}$中,即
$$
c_{i}=\sum_{j_{1}=0}^{B-1}A^{-1}_{j_{1},i_{1}}\sum_{x=0}^{B-1}A_{x,j_{1}}\sum_{y=0}^{B-1}A_{y,j_{1}}\sum_{0\le p_{0},q_{0}<B^{k},p_{0}\oplus q_{0}=i_{0}}d_{x,p_{0}}e_{y,q_{0}}=\sum_{0\le p_{0},q_{0}<B^{k},p_{0}\oplus q_{0}=i_{0}}\sum_{j_{1}=0}^{B-1}A^{-1}_{j_{1},i_{1}}\sum_{x=0}^{B-1}A_{x,j_{1}}d_{x,p_{0}}\sum_{y=0}^{B-1}A_{y,j_{1}}e_{y,q_{0}}
$$
对于$p_{0}$和$q_{0}$,构造$u_{i}=d_{i,p_{0}}$以及$v_{i}=e_{i,q_{0}}$,将两者作为$a_{i}$和$b_{i}$进行计算,关于$x$的枚举也就是算出$u'_{j_{1}}$,第二个关于$y$的枚举也就是$v'_{j_{1}}$,两者对应位置相乘,也就是$c'_{j_{1}}$,再乘上前面的$A_{j_{1},i_{1}}^{-1}$,也就是$c_{i_{1}}$

(这里的$c'_{j_{1}}$和$c_{i_{1}}$指代入$u_{i}$和$v_{i}$后用前面的方式计算得到,与之前的$c'_{i}$与$c_{i}$无关)

进一步的,根据归纳有$c_{i_{1}}=(u\otimes v)_{i_{1}}=\sum_{0\le p_{1},q_{1}<B,p_{1}\oplus q_{1}=i_{1}}u_{p_{1}}v_{q_{1}}$,代入即
$$
c_{i}=\sum_{0\le p_{0},q_{0}<B^{k},p_{0}\oplus q_{0}=i_{0}}\sum_{0\le p_{1},q_{1}<B,p_{1}\oplus q_{1}=i_{1}}a_{p_{0}B+p_{1}}b_{q_{0}B+q_{1}}=\sum_{0\le p,q<B^{k+1},p\oplus q=i}a_{p}b_{q}=(a\otimes b)_{i}
$$
(最后就利用到了$\oplus$是按位运算的)

确定矩阵$A$的条件后,我们还要具体的构造出一个矩阵$A$,通过矩阵左上角$B\times B$的部分就可以根据第二个条件唯一确定$A$了,也就是如何构造$n=B$时的矩阵

不难发现这就是一个幂次对$B$取模的加法卷积,联系FFT,记$\omega=\cos\frac{2\pi}{B}+\sin\frac{2\pi}{B}i$,取$A_{i,j}=\omega^{ij}$,逆矩阵将则令$A^{-1}_{i,j}=\frac{\omega^{-(ij)}}{B}$,下面来证明一下:

当我们确定了$A_{i,j}=\omega^{i}$,相当于将$a_{i}$看作一个$B$次多项式,求出其在$\omega^{i}$的值

根据余数定理,当我们知道一个多项式在$x=\omega^{i}$上的值,事实上也就是该多项式模$x-\omega^{i}$后的结果,而求出了所有$\omega^{i}$,那么也就知道了原多项式对$\prod_{i=0}^{B-1}(x-\omega^{i})$取模的结果

再将点值相乘, 也就确定了最终多项式对$\prod_{i=0}^{B-1}(x-\omega^{i})$取模后的结果

注意到$\omega$满足$\omega^{B}=1$且$\forall 1\le i<B,\omega^{i}\ne 1$,则$\prod_{i=0}^{B-1}(x-\omega^{i})=x^{B}-1$,而$x^{n}\equiv x^{n\ mod\ B}(mod\ x^{B}-1)$,因此恰好也就求出了下标对$B$取模的卷积结果

关于$\prod_{i=0}^{B-1}(x-\omega^{i})=x^{B}-1$,由于其可以看作$B$对点值$\{x=\omega^{i},y=0\}$,且每一个$x$各不相同,由此恰好可以确定一个$B$次多项式,且$x^{B}-1$恰好满足此性质,因此即相等

然而,本题需要对$p$取模,如果用实数表示的误差无法解决,代入$B=3$,可得$\omega=\frac{\sqrt{3}}{2}i-\frac{1}{2}$

考虑题中关于$p$的限制:不存在正整数$x,y$满足$\frac{1}{x}+\frac{1}{y}=\frac{3}{p}$

若$p\equiv 0(mod\ 3)$,取$x=y=\frac{2p}{3}$即满足条件,因此$\frac{1}{3}$在模$p$意义下有意义,但并不能保证3在模$p$意义下有二次剩余,换言之$\sqrt{3}$不一定有意义($\frac{1}{2}$有意义也可以证,但不关心)

为了使系数为整数,考虑将$\omega$作为一个整体,显然每一个虚数与$a+b\omega$一一对应,同时根据$\omega^{3}=1$以及$\omega^{2}=-\omega-1$(这两个条件也就是根据$\prod_{i=0}^{B-1}(x-\omega^{i})=x^{B}-1$得到),当产生高次项也都可以降为一次来表示

最终答案必然是整数,因此$b=0$,即为$a$

另外,计算矩阵乘法可以利用条件2来做,以由$a$计算$a'$为例子,即
$$
a'_{i}=\sum_{j=0}^{B^{k}-1}a_{j}A_{j,i}=\sum_{j_{1}=0}^{B-1}A_{j_{1},i_{1}}\sum_{j_{0}=0}^{B^{k-1}-1}a_{j_{0}B+j_{1}}A_{j_{0},i_{0}}
$$
对于每一个$j_{1}$,后面也就是一个$B^{k-1}$规模的子问题(矩阵乘法),递归后将其求出后,再代入该式即可,这样单次矩乘时间复杂度为$o(kB^{k+1})$

由于要快速幂,总复杂度为$o((m+\log_{2}t)3^{m})$可以通过

 

补充一下与本题无关的一些事情:

$B=2$时这个问题就是FWT,且做法与其完全相同

当$B$足够大时即为FFT,但时间复杂度会退化为$o(n^{2})$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 600005
 4 #define M 13
 5 int n,m,t,mod,S[N],base[N][M],b[M][M];
 6 struct Complex{
 7     int a,b;
 8     Complex(){
 9         a=b=0;
10     }
11     Complex(int x){
12         a=x,b=0;
13     }
14     Complex(int x,int y){
15         a=x,b=y;
16     }
17     Complex operator + (const Complex &k)const{
18         return Complex((a+k.a)%mod,(b+k.b)%mod);
19     }
20     Complex operator * (const Complex &k)const{
21         int s=mod-1LL*b*k.b%mod;
22         return Complex((1LL*a*k.a+s)%mod,(1LL*a*k.b+1LL*b*k.a+s)%mod);
23     }
24 }inv3,A[3][3],invA[3][3],a[N],ans[N];
25 Complex pow(Complex n,int m){
26     Complex s=n,ans=Complex(1);
27     while (m){
28         if (m&1)ans=ans*s;
29         s=s*s;
30         m>>=1;
31     }
32     return ans;
33 }
34 void DFT(Complex *a){
35     Complex aa[3];
36     for(int i=0,s=1;i<m;i++,s*=3)
37         for(int j=0;j<n;j++)
38             if (!base[j][i]){
39                 for(int k=0;k<3;k++)aa[k]=Complex();
40                 for(int k=0;k<3;k++)
41                     for(int l=0;l<3;l++)aa[k]=aa[k]+a[j+l*s]*A[l][k];
42                 for(int k=0;k<3;k++)a[j+k*s]=aa[k];
43             }
44 }
45 void IDFT(Complex *a){
46     Complex aa[3];
47     for(int i=0,s=1;i<m;i++,s*=3)
48         for(int j=0;j<n;j++)
49             if (!base[j][i]){
50                 for(int k=0;k<3;k++)aa[k]=Complex();
51                 for(int k=0;k<3;k++)
52                     for(int l=0;l<3;l++)aa[k]=aa[k]+a[j+l*s]*invA[l][k];
53                 for(int k=0;k<3;k++)a[j+k*s]=aa[k];
54             }
55 }
56 int main(){
57     scanf("%d%d%d",&m,&t,&mod);
58     n=1;
59     for(int i=1;i<=m;i++)n*=3;
60     for(int i=0;i<n;i++){
61         S[i]=S[i/3]+(i%3==1);
62         base[i][0]=i%3;
63         for(int j=1;j<m;j++)base[i][j]=base[i/3][j-1];
64     }
65     int k=mod,phi=mod;
66     for(int i=2;i*i<=k;i++)
67         if (k%i==0){
68             phi=phi/i*(i-1);
69             while (k%i==0)k/=i;
70         }
71     if (k>1)phi=phi/k*(k-1);
72     inv3=pow(Complex(3),phi-1);
73     for(int i=0;i<3;i++)
74         for(int j=0;j<3;j++){
75             A[i][j]=pow(Complex(0,1),i*j);
76             invA[i][j]=pow(Complex(0,1),6-i*j)*inv3;
77         }
78     for(int i=0;i<n;i++){
79         scanf("%d",&k);
80         a[i]=Complex(k);
81     }
82     for(int i=0;i<=m;i++)
83         for(int j=0;j<=m-i;j++)scanf("%d",&b[i][j]);
84     for(int i=0;i<n;i++){
85         k=0;
86         for(int j=m-1;j>=0;j--)
87             if (!base[i][j])k=k*3;
88             else k=k*3+3-base[i][j];
89         ans[i]=Complex(b[S[i]][S[k]]);
90     }
91     DFT(a);
92     DFT(ans);
93     for(int i=0;i<n;i++)ans[i]=a[i]*pow(ans[i],t);
94     IDFT(ans);
95     for(int i=0;i<n;i++)printf("%d\n",ans[i].a);
96 } 
View Code

 

posted @ 2021-03-06 13:08  PYWBKTDA  阅读(165)  评论(0编辑  收藏  举报