「题解」ARC151D Binary Representations and Queries

「题解」ARC151D Binary Representations and Queries

克罗内克积(Kronecker Product)

大小为 m×n 的矩阵 A 和大小为 p×q 的矩阵 B 的克罗内克积 AB 被定义为:

(a1,1Ba1,nBam,1Bam,nB)

显然不满足交换律,但是容易验证其满足结合律。

性质 1:(AB)(CD)=(AC)(BD),其中 AC 表示矩阵 AC 的乘积。证明直接按定义写出矩阵来即可。

推论 1:(A1B1Z1)(A2B2Z2)(AnBnZn)=(A1A2An)(B1B2Bn)(Z1Z2Zn)

根据性质 1,不难通过每次取出每个括号的最前面的矩阵来证明。

推论 2:

假设 A,B,C,In 是大小为 n×n 的矩阵,其中 In 为单位矩阵。那么即有:ABC=(AInIn)(InBIn)(InInC)=(AInIn)(InBIn)(InInC)

同样可以扩展到 k 个矩阵的情况。

再根据推论 1 将最后一个式子拆开,然后再以任意的方式合并,可以得出相邻的两个括号中间的矩阵 A 在夹在 In 中不同的位置时可以任意交换,而夹在相同的位置时则不行。

也就是 (AInIn)(InBIn)=(InBIn)(AInIn) 成立,但不会有 (AInIn)(BInIn)=(BInIn)(AInIn)

(不难理解,n=1 相当于矩阵乘法具有交换律了)

回到 ARC151D,对于仅有一个长度为 2 的向量 a 的特殊情况,构造矩阵 A0,A1 使得操作 Y=0 时等价于 aA0a,操作 Y=1 时等价于 aA1a

仿照 FWT 的方法,对于长度为 2n 的向量 a 如果只想对第 X 位进行操作,那么相当于 a(I2I2AYI2I2)a,这里一共有 n 个大小为 2×2 的矩阵,AY 在第 X 个(最开头为第 0 个)。

根据结论,可以将 AY 处在不同位置的矩阵进行交换,但是 AY 相同的则不能。先将 X 相同的矩阵移动到一起,再根据推论 1 可以将同一 X 的矩阵乘在一起看作一个矩阵 BX

那么现在问题就变成了计算 (B0In)(InB1In)(InInBn)a

考虑左乘上一个 (InBiIn) 具体是在固定除了第 i 位以外的所有位置,然后单独对 i 这一位左乘上 Bi(人话:对于每个第 X0 的数 v,将 av,av+2X 构成的向量左乘 Bi

直接按照这个写,就是和平常写高维前缀和 / 高维后缀和的 FMT 写法一样。

或者按照 FWT_xor 的写法也可以,就是把第 i 层合并的时候进行的线性变换改成左乘上 Bi 这个样子。

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<random>
#include<assert.h>
#define pb emplace_back
#define mp make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n';
#define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n';
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef pair<ll,int>pli;
typedef pair<ll,ll>pll;
typedef pair<int,ll>pil;
typedef vector<int>vi;
typedef vector<ll>vll;
typedef vector<pii>vpii;
typedef vector<pil>vpil;
template<typename T>T cmax(T &x, T y){return x=x>y?x:y;}
template<typename T>T cmin(T &x, T y){return x=x<y?x:y;}
template<typename T>
T &read(T &r){
	r=0;bool w=0;char ch=getchar();
	while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar();
	while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar();
	return r=w?-r:r;
}
template<typename T1,typename... T2>
void read(T1 &x,T2& ...y){read(x);read(y...);}
const int mod=998244353;
inline void cadd(int &x,int y){x=(x+y>=mod)?(x+y-mod):(x+y);}
inline void cdel(int &x,int y){x=(x-y<0)?(x-y+mod):(x-y);}
inline int add(int x,int y){return (x+y>=mod)?(x+y-mod):(x+y);}
inline int del(int x,int y){return (x-y<0)?(x-y+mod):(x-y);}
int qpow(int x,int y){
	int s=1;
	while(y){
		if(y&1)s=1ll*s*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return s;
}
const int N=18;
int n,q;
int a[(1<<N)+10];
int f[N][2][2];
int g[2][2][2],h[2][2];
void FWT(){
	for(int o=2,k=1,c=0;c<n;o<<=1,k<<=1,++c){
		for(int i=0;i<(1<<n);i+=o){
			for(int j=0;j<k;j++){
				int x=a[i+j],y=a[i+j+k];
				int u=add(1ll*x*f[c][0][0]%mod,1ll*y*f[c][0][1]%mod);
				int v=add(1ll*x*f[c][1][0]%mod,1ll*y*f[c][1][1]%mod);
				a[i+j]=u;a[i+j+k]=v;
			}
		}
	}
}
signed main(){
	#ifdef do_while_true
//		assert(freopen("data.in","r",stdin));
//		assert(freopen("data.out","w",stdout));
	#endif
	read(n);read(q);
	for(int i=0;i<(1<<n);i++)read(a[i]);
	for(int i=0;i<n;i++)f[i][0][0]=f[i][1][1]=1;
	g[0][0][0]=g[0][1][0]=g[0][1][1]=1;
	g[1][0][0]=g[1][0][1]=g[1][1][1]=1;
	while(q--){
		int x,y;read(x,y);
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				for(int k=0;k<2;k++)
					cadd(h[i][j],1ll*g[y][i][k]*f[x][k][j]%mod);
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				f[x][i][j]=h[i][j],h[i][j]=0;
	}
	FWT();
	for(int i=0;i<(1<<n);i++)cout << a[i] << ' ';
    #ifdef do_while_true
		cerr<<'\n'<<"Time:"<<1.0*clock()/CLOCKS_PER_SEC*1000<<" ms"<<'\n';
	#endif
	return 0;
}
posted @   do_while_true  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
历史上的今天:
2022-02-07 Miller–Rabin 素数测试
2022-02-07 杜教筛

This blog has running: 1845 days 1 hours 33 minutes 53 seconds

点击右上角即可分享
微信分享提示