首页 > 其他分享 >[NOI Online #3 提高组] 魔法值(矩阵快速幂+各种优化)

[NOI Online #3 提高组] 魔法值(矩阵快速幂+各种优化)

时间:2022-10-28 18:33:28浏览次数:63  
标签:魔法值 Matrix int 矩阵 异或 Online 乘法 优化 NOI

矩阵快速幂

相信其他巨佬讲矩阵快速幂的原理和过程都已经很详细了,这里我就着重讲一讲用裸的矩阵快速幂算法之后,如何优化。

优化1:优化矩阵乘法

这个好几位大佬讲过了,我也不讲了,主要就是把 \(O(n^3)\) 的矩阵乘法优化到 \(O(n^2)\)。

优化2:倍增预处理矩阵

倍增预处理矩阵的核心思想就是:

将 \(2^k\) 个转移矩阵相乘出来的矩阵预处理出来,并记录为 \(m_k\),那么通过 \(m_k=m_{k-1}^2\) 就可以用 \(32\) 次矩阵乘法把每个 \(m_i\) 算出来。

那么对于一次询问为 \(x\),也就是求 \(2^x\) 个转移矩阵相乘出来的矩阵,我们就可以通过类似倍增一样的算法在 \(\log(x)\) 次计算后计算出答案。

优化3:bitset

我们可以发现,在计算矩阵乘法时,可以用 bitset优化。

比如,对于矩阵 \(A\)、\(B\),现在要计算 \(C=A\times B\)。

那么根据定义,\(C_{i,j}=\operatorname{xor}_{k=1}^{n} A_{i,k}\times B_{k,j}\)。

形象地理解一下,\(C_{i,j}\) 的值就是 \(A\) 矩阵的第 \(i\) 行和 \(B\) 矩阵的第 \(j\) 列一位一位地乘起来,再把这些乘出来的结果异或起来。

而且我们知道一个性质,\(A\) 矩阵和 \(B\) 矩阵中只可能出现 \(0\) 或 \(1\)。

那么对于两个数 \(x,y\in\{0,1\}\),必定有 \(x\times y=x\operatorname{and}y\)。

这时容易想到用 bitset维护矩阵乘法。就是把矩阵每一行所代表的 \(01\) 串存进 bitset<100>row[100]内,把矩阵的每一列所代表的 \(01\) 串存进 bitset<100>line[100]内。然后 \(A\) 矩阵的第 \(i\) 行和 \(B\) 矩阵的第 \(j\) 列一位一位地乘起来就是 A.row[i]&B.line[j],这样我们就能解决乘法的问题了。

但是有一个问题,我们得到了乘出来的序列后,怎么把它们一个一个异或起来呢?注意到这个序列是个 \(01\) 序列,那么如果这个序列中 \(1\) 的个数为奇数,它们异或起来就是 \(1\),否则就是 \(0\),所以异或的部分我们就可以维护了,即 \(C_{i,j}=\operatorname{count}()\bmod2\)。

那么我们就顺利地把 \(O(n^3)\) 的矩阵乘法成功优化到 \(O(\frac{n^3}{64})\)。(未加优化1)

优化4:询问离线

感觉最没用的优化。

显然,我们每次询问都算一次 \(\operatorname{pow()}\),感觉会重复算了很多,所以不妨把询问给离线存下来,存进数组 \(q\) 里面,并对它进行排序。

这个排序可能会导致程序变慢而不是变快。

那么不妨假设我们现在已经知道了转移矩阵 \(t\) 的 \(q_i\) 次方是多少,要求 \(q_{i+1}\) 的询问,也就是要求出 \(t^{q_{i+1}}\)。那么我们只用求出 \(t^{q_{i+1}-q_i}\),然后再乘上上次算出来的矩阵,就可以省下一些时间。

优化5:O2 优化和 IO 读写

最后贴一下代码:(没有加优化1卡过去的)

#include<bits/stdc++.h>

#define N 110
#define LV 32

using namespace std;

struct Matrix
{
	bitset<N>row[N];//bitset优化
	bitset<N>line[N];
	Matrix()
	{
		memset(row,0,sizeof(row));
		memset(line,0,sizeof(line));
	}
}turn[LV],st;

struct Query
{
	unsigned int x;
	int id;
}ask[N];

int n,m,q;
unsigned int f[N],ans[N];
bool tmp[N][N];

inline Matrix operator * (Matrix a,Matrix b)
{
	Matrix ans;
	bitset<N>now;
	for(register int i=1;i<=n;i++)
	{
		for(register int j=1;j<=n;j++)
		{
			now=a.row[i]&b.line[j];//上述的计算方法
			if(now.count()&1)
			{
				ans.row[i].set(j);
				ans.line[j].set(i);
			}
		}
	}
	return ans;
}

inline Matrix poww(unsigned int x)//倍增版的快速幂
{
	Matrix ans=st;
	for(int i=31;i>=0;i--)
	{
		if(x>=(1u<<i))
		{
			x-=(1u<<i);
			ans=turn[i]*ans;
		}
	}
	return ans;
}

inline void prework()//矩阵预处理
{
	for(register int i=1;i<LV;i++)
		turn[i]=turn[i-1]*turn[i-1];
}

inline bool cmp(const Query a,const Query b)
{
	return a.x<b.x;
}

inline unsigned int getans(const Matrix a)
{
	unsigned int ans=0;
	for(register int i=1;i<=n;i++)
		if(a.line[1][i])
			ans^=f[i];
	return ans;
}

inline int read()
{
	unsigned int x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1u)+(x<<3u)+(ch^'0');
		ch=getchar();
	}
	return x;
}

int main()
{
	n=read();m=read();q=read();
	for(register int i=1;i<=n;i++)
		st.row[i].set(i),st.line[i].set(i);
	for(register int i=1;i<=n;i++)
		f[i]=read();
	for(register int i=1;i<=m;i++)
	{
		const int u=read(),v=read();
		turn[0].row[u].set(v),turn[0].line[v].set(u);
		turn[0].row[v].set(u),turn[0].line[u].set(v);
	}
	prework();
   //下面是询问离线
	for(register int i=1;i<=q;i++)
	{
		ask[i].x=read();
		ask[i].id=i;
	}
	sort(ask+1,ask+q+1,cmp);
	Matrix last=poww(ask[1].x);
	ans[ask[1].id]=getans(last);
	for(register int i=2;i<=q;i++)
	{
		last=last*poww(ask[i].x-ask[i-1].x);
		ans[ask[i].id]=getans(last);
	}
	for(register int i=1;i<=q;i++)
		printf("%u\n",ans[i]);
	return 0;
}

标签:魔法值,Matrix,int,矩阵,异或,Online,乘法,优化,NOI
From: https://www.cnblogs.com/ez-lcw/p/16837042.html

相关文章

  • NOIP 前 CF*2300 左右 dp 做题记录
    iFTL独立做出形象理解为两个横放的羽毛球盒,第一个放长t1的,第二个放长t2的,然后手推可得一次共同发射之后必是平平的盒子底部,仿佛回到了最初,至此可发现子结构。基于此......
  • ON1 NoNoise AI 2023 for mac(图片降噪软件)中文版
    ON1NoNoiseAIformac一款图片降噪软件,ON1NoNoiseAI中文版智能去除所有图像噪点,同时智能恢复和增强细节。它通过支持常见的照片编辑器和文件格式集成到您的工作流程中,......
  • 洛谷 P1077 [NOIP2012 普及组] 摆花 (DP)
    https://www.luogu.com.cn/problem/P1077题目描述摆上m盆花。一共有n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同......
  • [Ynoi2016] 掉进兔子洞
    \(\text{Solution}\)莫队配合\(\text{bitset}\)发现答案困难的部分在于同一个数在三个区间出现次数的最小值考虑强行拆开看,用莫队处理出每个区间每个数的出现次数,这个......
  • 2022NOIPA层联测16
    数塔:相等上传非常显然,重点是怎么二分(对于这种不知道更大的更优还是更小的更优的题,不知道选哪个二分模板。。)大于等于和小于等于都可以,重要的是取等,就是保证答案在二分......
  • 洛谷P3225 [HNOI2012]矿场搭建
    SLOJH7136.「HNOI2012」矿场搭建题目描述煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援......
  • noi.cn 访问量爬取
    网课期间开始的一项无聊的项目,对noi.cn的访问量进行爬取。具体操作为直接访问对应的网址,获取其网站底部的总访问量信息。爬虫使用Python编写,配合bat文件和Windows......
  • 接水问题(NOIP 2010 PJT2)
      这个的思路就是让各个水龙头所用的时间尽可能地接近,可以先向优先队列中推入前m个数,由于开的是小根堆最小的数在前面我们把它拿出来,加上下一个人所需的时间。如此反复......
  • [NOI2002] 荒岛野人
    exgcd简单题首先容易想到先枚举m,然后判断。至于判断只需用联立方程,先给ci-1\(c_i+p_i\timest\equivx\pmodm\)\(c_j+p_j\timest\equivx\pmodm\)即\(......
  • NOI2022 游记
    一切尘埃落定。我仿佛刚从乱石堆中满面灰尘地爬出来,精疲力尽地坐在地上,放眼望去,只有一片片残败的废墟。想挣扎着站起来寻找同伴的时候,却仿佛顶着一座大山,直不起身来。心中......