LG6569 魔法值

魔法值

H 国的交通由 \(n\) 座城市与 \(m\) 条道路构成,城市与道路都从 \(1\) 开始编号,其中 \(1\) 号城市是 H 国的首都。H 国中一条道路将把两个不同城市直接相连,且任意两个城市间至多有一条道路。

H 国是一个信奉魔法的国家,在第 \(j\) 天,\(i\) 号城市的魔法值为 \(f_{i,j}\)。H 国的魔法师已观测到第 0 天时所有城市的魔法值 \(f_{i,0}\),且他们还发现,之后的每一天每个城市的魔法值,都将会变为所有与该城市直接相连的城市的前一天魔法值的异或值,即

\[f_{x,j}=f_{v_1,j-1}\oplus f_{v_2,j-1}\oplus \cdots\oplus f_{v_k,j-1} \]

其中 \(j\ge 1\)\(v_1,v_2,\cdots,v_k\) 是所有与 \(x\) 号城市直接相连的城市,\(\oplus\) 为异或运算。

现在 H 国的国王问了你 \(q\) 个问题,对于第 \(i\)\(1\le i\le q\))个问题你需要回答:第 \(a_i\) 天时首都的魔法值是多少。

对于 \(100\%\) 的数据,满足 \(1 \leq n,q \leq 100\)\(1 \leq m \leq \frac{n(n-1)}{2}\)\(1\leq a_i < 2^{32}\)\(0\leq f_i < 2^{32}\)

题解

https://www.luogu.com.cn/blog/fusu2333/solution-p6569

把题目的式子写的更清晰一点:设 \(e_{u, v}\) 表示 \((u, v)\) 之间是否有边,有边为 \(1\) ,无边为 \(0\) ,再把题目里的 \(f\) 的两个下角标交换一下,即设 \(f_{i, j}\) 是在第 \(i\) 天,城市 \(j\) 的魔法值,则有:

\[f_{i, v} = \operatorname{xor}_{u = 1}^n f_{i - 1, u} \times e_{u, v} \]

现在定义一个 \(a \times b\) 矩阵 \(A\) 异或一个 \(b \times c\) 矩阵 \(B\) 的结果为一个 \(a \times c\) 的矩阵 \(C\) ,转移为

\[C_{i, j} = \operatorname{xor}_{k = 1}^b A_{i, k} \times B_{k, j} \]

\(1 \times n\) 矩阵 \(F_i\) 的第 \(1\) 行第 \(j\) 列表示第 \(i\) 天城市 \(j\) 的魔法值, \(n \times n\) 矩阵 \(E\) 的第 \(i\) 行第 \(j\) 列表示 \(i, j\) 之间是否有边,可以发现 \(F_i\) 是由 \(F_{i - 1}\) 异或矩阵 \(E\) 转移而来。

\[F_i = F_{i - 1} \operatorname{xor} E \]

式子看起来长得很像快速幂,快速幂的要求矩阵有结合律,即 \((A \operatorname{xor} B \operatorname{xor} C)_{i, j} = (A \operatorname{xor} (B \operatorname{xor} C))_{i, j}\) ,来尝试推一下。(下面省略两矩阵间的 \(\operatorname{xor}\) 运算符)

\(A\)\(n \times p\) 矩阵, \(B\)\(p \times q\) 矩阵, \(C\)\(q \times m\) 矩阵,则他们的异或和为 \(n \times m\) 矩阵。

\[\begin{aligned}(ABC)_{i, j} = \operatorname{xor}_{x = 1}^q(\operatorname{xor}_{y = 1}^p A_{i, y} \times B_{y, x}) \times C_{x, j} \end{aligned} \]

需要注意的是,一般情况下,乘法对异或没有分配律。例如对于 \(3, 1, 2\)\(3 \times (1 \operatorname{xor} 2) = 9 \neq (1 \times 3)\operatorname{xor}(2 \times 3) = 5\) ,因此不能直接去掉上式中的括号。

但是注意到 C 矩阵一定是一个 \(01\) 矩阵(显然如果进行快速幂,那么一个 \(01\) 矩阵在只做乘法和异或的情况下一定不存在进位,结果还是一个 \(01\) 矩阵)。考虑当 \(C_{x, j} = 0\)\(1\) 时,将括号去掉把 \(C_{x, j}\) 乘进去,式子是成立的。证明上可以考虑当 \(C_{x, j} = 0\) 时,括号乘上 \(C_{x, j}\) 的结果一定是 \(0\) ,将 \(C_{x, j}\) 乘进去后,每一项都是 \(0\) ,异或和还是 \(0\) ;当 \(C_{x, j} = 1\) 时,括号内每一项的值都没有发生改变。而整个括号的值乘上 \(1\) 的值也不会改变,因此二者是相等的。

由此得到

\[\begin{aligned}(ABC)_{i, j} = \operatorname{xor}_{x = 1}^q \operatorname{xor}_{y = 1}^p A_{i, y} \times B_{y, x} \times C_{x, j} \end{aligned} \]

同理,对于 \((A(BC))_{i, j}\) ,也可以写出式子后用同样的证明去括号,因此二者是相等的。在 \(C\)\(01\) 矩阵时,矩阵异或具有结合律,可以进行快速幂。

因此有

\[F_{i} = F_0 \operatorname{xor} E^i \]

这里 \(E^i\)\(E\) 自身异或 \(i\) 次。

那么有一个 naive 的做法是每次询问都进行一次矩阵快速幂, \(F_{a_i} = E^{a_i}\) 。时间复杂度为 \(O(n^3q \log a)\) 。期望得分 \(40\) 分。

注意到对于询问,如果对 \(E\) 进行快速幂的话,由于 \(E\)\(n \times n\) 的矩阵,因此做一次的复杂度就为 \(O(n^3)\) 。但是 \(F\)\(1 \times n\) 的矩阵,因此 \(F\) 每次异或一个 \(E\) 的幂的复杂度为 \(O(n^2)\) 。考虑不进行快速幂,对 \(a_i\) 进行二进制拆分,拆成 \(O(\log a)\)\(2\) 的幂的形式 ,首先预处理出 \(E^{2^k}\) 的值,然后用 \(F\) 依次乘上对应的幂即可。

预处理的复杂度为 \(O(n^3 \log a)\) ,单次询问的复杂度为 \(O(n^2 \log a)\) 。因此总复杂度 \(O(n^3 \log a) - O(n^2q \log a)\)

另外回复一下评论区疑问,上式复杂度中的 - 不代表减号。对于一个算法,用 \(A-B\) 表示其预处理部分为 \(A\) 的复杂度, \(B\) 表示其余部分的时间复杂度。

CO int N=101;
int n;
uint a[N];

struct matrix {int v[N][N];} G[32];

matrix operator*(CO matrix&A,CO matrix&B){
	matrix C={};
	for(int k=1;k<=n;++k)
		for(int j=1;j<=n;++j)if(B.v[k][j])
			for(int i=1;i<=n;++i)
				C.v[i][j]^=A.v[i][k]*B.v[k][j];
	return C;
}

int main(){
	read(n);
	int m=read<int>(),q=read<int>();
	for(int i=1;i<=n;++i) read(a[i]);
	while(m--){
		int x=read<int>(),y=read<int>();
		G[0].v[x][y]=G[0].v[y][x]=1;
	}
	for(int i=1;i<=31;++i) G[i]=G[i-1]*G[i-1];
	while(q--){
		uint t=read<uint>();
		matrix F={};
		for(int i=1;i<=n;++i) F.v[i][1]=a[i];
		for(int i=0;i<=31;++i)if(t>>i&1) F=G[i]*F;
		printf("%u\n",F.v[1][1]);
	}
	return 0;
}

posted on 2020-05-25 19:09  autoint  阅读(214)  评论(0编辑  收藏  举报

导航