【三进制FWT】UOJ272 [清华集训2016] 石家庄的工人阶级队伍比较坚强

【前言】
昨天模拟题可以用高进制下的 FWT \text{FWT} FWT做,根据sc的说法我写了一次,然后又弄了一会,就来写个板子。

吐槽一下居然还要卡常,我把乘一个 ω , ω 2 \omega,\omega ^2 ω,ω2改成直接进行变换才过了。
用时除等于二。

【题目】
UOJ
n = 3 m n=3^m n=3m,有 n n n个人玩石头剪刀布,一共 t t t轮游戏,每轮游戏出 m m m次。每个人的出法固定为其编号的三进制表示下的数字。令 b x , y b_{x,y} bx,y表示两个人玩,第一个人赢了第二个人 u u u次,输了 v v v次的权值。每个人初始有一个权值 f 0 , i f_{0,i} f0,i,在第 k k k轮,第 x x x个人的权值是:
f k , x = ∑ 0 ≤ y &lt; n f k − 1 , y b u , v f_{k,x}=\sum_{0\leq y&lt;n} f_{k-1,y} b_{u,v} fk,x=0y<nfk1,ybu,v
权值对 p p p取模,求每个人最终的权值。
m ≤ 12 , t ≤ 1 0 9 , 2 ∤ p , 3 ∤ p m\leq 12,t\leq 10^9, 2 \nmid p, 3 \nmid p m12,t109,2p,3p

【解题思路】
懒得写题解,以下来自dalao虽然贴也好累啊

转移关系都是固定的,设它为矩阵 B B B,那么要求的就是 f n = f 0 B n f_n=f_0B^n fn=f0Bn

然后我们定义三进制不进位加法 ⊕ \oplus 和三进制不退位减法 ⊖ \ominus ,根据 B B B的定义以及石头剪刀布的性质可以得到 ∀ k &lt; 3 m , B i ⊕ k , j ⊕ k = B i , j \forall k \lt 3^m,B_{i\oplus k,j\oplus k}=B_{i,j} k<3m,Bik,jk=Bi,j

那么易得 B i , j = B i ⊖ j , 0 B_{i,j}=B_{i\ominus j,0} Bi,j=Bij,0,将这个结论推广到 B n B^n Bn,就有 ∀ k &lt; 3 m , B i ⊕ k , j ⊕ k n = B i , j n \forall k \lt 3^m,B^n_{i\oplus k,j\oplus k}=B^n_{i,j} k<3m,Bik,jkn=Bi,jn,可以使用归纳法证明。

对于 f n = f 0 B n f_n=f_0B^n fn=f0Bn,它的第 i i i项为:
f n , i = ∑ k f 0 , k B k , i n = ∑ k f 0 , k B 0 , i ⊖ k n = ∑ x ⊕ y = i f 0 , x B 0 , y n f_{n,i}=\sum_k f_{0,k}B^n_{k,i}=\sum_k f_{0,k}B^n_{0,i\ominus k}=\sum_{x\oplus y=i}f_{0,x}B^n_{0,y} fn,i=kf0,kBk,in=kf0,kB0,ikn=xy=if0,xB0,yn
那么这个就是一个异或卷积的形式,而且我们只需要第一行,又因为
B 0 , i n = ∑ k B 0 , k n B k , i = ∑ k B 0 , k n B 0 , i ⊖ k = ∑ x ⊕ y = i B 0 , x n B 0 , y B^n_{0,i}=\sum_k B^n_{0,k}B_{k,i}=\sum_k B^n_{0,k}B_{0,i\ominus k}=\sum_{x\oplus y=i} B^n_{0,x}B_{0,y} B0,in=kB0,knBk,i=kB0,knB0,ik=xy=iB0,xnB0,y
我们只需要对 B B B的第一行做 n n n次卷积,然后 f f f再和它卷积即可。

然后就是三进制下的 FWT \text{FWT} FWT了,我们需要一个三次单位根 ω \omega ω,然后复数可以表示成 a + b ω a+b\omega a+bω的形式,由于有 ω 2 + ω + 1 = 0 \omega ^2+\omega +1=0 ω2+ω+1=0,所以 ω 2 = − ω − 1 \omega ^2 =-\omega -1 ω2=ω1,运算过程中由于系数均为 0 / 1 / − 1 0/1/-1 0/1/1,所以不需要取模。

接下来我们可以定义复数乘法:
( a + b ω ) ( c + d ω ) = a c + ( a d + b c ) ω + b d ( − ω − 1 ) = ( a c − b d ) + ( a d + b c − b d ) ω (a+b\omega)(c+d\omega)=ac+(ad+bc)\omega+bd(-\omega-1)=(ac-bd)+(ad+bc-bd)\omega (a+bω)(c+dω)=ac+(ad+bc)ω+bd(ω1)=(acbd)+(ad+bcbd)ω
然后就有
A = [ 1 1 1 1 ω ω 2 1 ω 2 ω ] A= \left[ \begin{matrix} 1 &amp; 1 &amp; 1 \\ 1 &amp; \omega &amp; \omega^2 \\ 1 &amp; \omega^2 &amp; \omega \end{matrix} \right] A=1111ωω21ω2ω
以及
[ 1 1 1 1 ω ω 2 1 ω 2 ω ] × [ 1 1 1 1 ω 2 ω 1 ω ω 2 ] = 3 E \left[ \begin{matrix} 1 &amp; 1 &amp; 1 \\ 1 &amp; \omega &amp; \omega^2 \\ 1 &amp; \omega^2 &amp; \omega \end{matrix} \right]\times \left[ \begin{matrix} 1 &amp; 1 &amp; 1 \\ 1 &amp; \omega^2 &amp; \omega \\ 1 &amp; \omega &amp; \omega^2 \end{matrix} \right]=3E 1111ωω21ω2ω×1111ω2ω1ωω2=3E
由于每次 IDFT \text{IDFT} IDFT的时候多乘了一个 3 3 3,总共 log ⁡ 3 n \log_{3}n log3n层,因此最后只需要讲所有数除以一个 n n n即可。

复杂度 O ( n m + n log ⁡ t ) O(nm+n\log t) O(nm+nlogt)

补充:高进制 FWT \text{FWT} FWT的矩阵及逆矩阵

这是异或的:
A = [ 1 1 1 ⋯ 1 1 w n w n 2 ⋯ w n n − 1 1 w n 2 w n 4 ⋯ w n 2 ( n − 1 ) ⋮ ⋮ ⋮ ⋱ ⋮ 1 w n ( n − 1 ) w n 2 ( n − 1 ) ⋯ w n ( n − 1 ) ( n − 1 ) ] A= \begin{bmatrix} 1&amp; 1 &amp; 1&amp; \cdots&amp; 1\\ 1&amp; w_n&amp; w_n^2&amp; \cdots &amp; w_n^{n - 1}\\ 1&amp; w_n^{2} &amp; w_n^{4}&amp; \cdots &amp; w_n^{2(n- 1)}\\ \vdots&amp; \vdots &amp; \vdots&amp; \ddots &amp; \vdots \\ 1&amp; w_n^{(n - 1)}&amp; w_n^{2(n - 1)} &amp; \cdots &amp; w_n^{(n - 1)(n - 1)} \end{bmatrix} A=11111wnwn2wn(n1)1wn2wn4wn2(n1)1wnn1wn2(n1)wn(n1)(n1)

A T = 1 n [ 1 1 1 ⋯ 1 1 w n − 1 w n − 2 ⋯ w n − ( n − 1 ) 1 w n − 2 w n − 4 ⋯ w n − 2 ( n − 1 ) ⋮ ⋮ ⋮ ⋱ ⋮ 1 w n − ( n − 1 ) w n − 2 ( n − 1 ) ⋯ w n − ( n − 1 ) ( n − 1 ) ] A^{T}= \frac 1 n\begin{bmatrix} 1&amp; 1 &amp; 1&amp; \cdots&amp; 1\\ 1&amp; w_n^{-1}&amp; w_n^{-2}&amp; \cdots &amp; w_n^{-(n - 1)}\\ 1&amp; w_n^{-2} &amp; w_n^{-4}&amp; \cdots &amp; w_n^{-2(n- 1)}\\ \vdots&amp; \vdots &amp; \vdots&amp; \ddots &amp; \vdots \\ 1&amp; w_n^{-(n - 1)}&amp; w_n^{-2(n - 1)} &amp; \cdots &amp; w_n^{-(n - 1)(n - 1)} \end{bmatrix} AT=n111111wn1wn2wn(n1)1wn2wn4wn2(n1)1wn(n1)wn2(n1)wn(n1)(n1)

这是与的,相当于做一个后缀和,逆运算是差分。
A = [ 1 1 1 ⋯ 1 0 1 1 ⋯ 1 0 0 1 ⋯ 1 ⋮ ⋮ ⋮ ⋱ ⋮ 0 0 0 ⋯ 1 ] A= \begin{bmatrix} 1&amp; 1 &amp; 1&amp; \cdots&amp; 1\\ 0&amp; 1&amp; 1&amp; \cdots &amp; 1\\ 0&amp; 0 &amp; 1&amp; \cdots &amp; 1\\ \vdots&amp; \vdots &amp; \vdots&amp; \ddots &amp; \vdots \\ 0&amp; 0&amp; 0 &amp; \cdots &amp; 1 \end{bmatrix} A=1000110011101111

这是或的,相当于做一个前缀和,逆运算是差分。
A = [ 1 0 0 ⋯ 0 1 1 0 ⋯ 0 1 1 1 ⋯ 0 ⋮ ⋮ ⋮ ⋱ ⋮ 1 1 1 ⋯ 1 ] A= \begin{bmatrix} 1&amp; 0 &amp; 0&amp; \cdots&amp; 0\\ 1&amp; 1&amp; 0&amp; \cdots &amp; 0\\ 1&amp; 1 &amp; 1&amp; \cdots &amp; 0\\ \vdots&amp; \vdots &amp; \vdots&amp; \ddots &amp; \vdots \\ 1&amp; 1&amp; 1 &amp; \cdots &amp; 1 \end{bmatrix} A=1111011100110001

【参考代码】

#include<bits/stdc++.h>
using namespace std;

const int N=6e5+10;
int n,m,T,mod;
int a[N],b[15][15];

namespace IO
{
	int read()
	{
		int ret=0;char c=getchar();
		while(!isdigit(c)) c=getchar();
		while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
		return ret;
	}
	void write(int x){if(x>9)write(x/10);putchar(x%10^48);}
	void writeln(int x){write(x);putchar('\n');}
}
using namespace IO;

int upm(int x){return x>=mod?x-mod:x<0?x+mod:x;}
int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
void exgcd(int &x,int &y,int a,int b){if(!b)return (void)(x=1,y=0);exgcd(y,x,b,a%b),y-=a/b*x;}
int inv(int a){int x,y;exgcd(x,y,a,mod);return (x%mod+mod)%mod;}

struct cd
{
	int x,y;
	cd(int _x=0,int _y=0):x(_x),y(_y){}
	cd operator + (const cd&a){return cd(upm(x+a.x),upm(y+a.y));}
	cd operator - (const cd&a){return cd(upm(x-a.x),upm(y-a.y));}
	cd operator * (const cd&a){return cd(upm(mul(x,a.x)-mul(y,a.y)),upm(upm(mul(x,a.y)+mul(y,a.x))-mul(y,a.y)));}
};
cd f[N],g[N];

cd w1(const cd&a){return cd(upm(-a.y),upm(a.x-a.y));}//w1=cd(0,1)
cd w2(const cd&a){return cd(upm(a.y-a.x),upm(-a.x));}//w2=cd(mod-1,mod-1)=w1*w1
void fwt(cd *a,int n)
{
	for(int i=1;i<n;i*=3)
		for(int j=0;j<n;j+=i*3)
			for(int k=0;k<i;++k)
			{
				cd x=a[j+k],y=a[j+k+i],z=a[j+k+(i<<1)];
				a[j+k]=x+y+z;a[j+k+i]=x+w1(y)+w2(z);a[j+k+(i<<1)]=x+w2(y)+w1(z);
			}
}
void ifwt(cd *a,int n)
{
	for(int i=1;i<n;i*=3)
		for(int j=0;j<n;j+=i*3)
			for(int k=0;k<i;++k)
			{
				cd x=a[j+k],y=a[j+k+i],z=a[j+k+(i<<1)];
				a[j+k]=x+y+z;a[j+k+i]=x+w2(y)+w1(z);a[j+k+(i<<1)]=x+w1(y)+w2(z);
			}	
}

cd qpow(cd x,int y)
{
	cd res=cd(1,0);
	for(;y;y>>=1,x=x*x) if(y&1) res=res*x;
	return res;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("UOJ272.in","r",stdin);
	freopen("UOJ272.out","w",stdout);
#endif
	m=read();T=read();mod=read();n=1;
	for(int i=1;i<=m;++i) n*=3;
	if(mod==1){for(int i=0;i<n;++i)puts("0");return 0;}
	for(int i=0;i<n;++i) a[i]=read();
	for(int i=0;i<=m;++i) for(int j=0;j<=m-i;++j) b[i][j]=read();
	for(int i=0;i<n;++i)
	{
		int tmp=i,cntw=0,cntl=0;
		for(;tmp;tmp/=3)
		{
			int j=tmp%3;
			j==1?++cntw:j==2?++cntl:0;
		}
		g[i].x=b[cntw][cntl];f[i].x=a[i];
	} 
	fwt(f,n);fwt(g,n);
	for(int i=0;i<n;++i) f[i]=f[i]*qpow(g[i],T);
	ifwt(f,n);
	for(int i=0,iv=inv(n);i<n;++i) writeln(mul(f[i].x,iv)); 
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值