LG6569 魔法值
魔法值
H 国的交通由 \(n\) 座城市与 \(m\) 条道路构成,城市与道路都从 \(1\) 开始编号,其中 \(1\) 号城市是 H 国的首都。H 国中一条道路将把两个不同城市直接相连,且任意两个城市间至多有一条道路。
H 国是一个信奉魔法的国家,在第 \(j\) 天,\(i\) 号城市的魔法值为 \(f_{i,j}\)。H 国的魔法师已观测到第 0 天时所有城市的魔法值 \(f_{i,0}\),且他们还发现,之后的每一天每个城市的魔法值,都将会变为所有与该城市直接相连的城市的前一天魔法值的异或值,即
其中 \(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\) 的魔法值,则有:
现在定义一个 \(a \times b\) 矩阵 \(A\) 异或一个 \(b \times c\) 矩阵 \(B\) 的结果为一个 \(a \times c\) 的矩阵 \(C\) ,转移为
设 \(1 \times n\) 矩阵 \(F_i\) 的第 \(1\) 行第 \(j\) 列表示第 \(i\) 天城市 \(j\) 的魔法值, \(n \times n\) 矩阵 \(E\) 的第 \(i\) 行第 \(j\) 列表示 \(i, j\) 之间是否有边,可以发现 \(F_i\) 是由 \(F_{i - 1}\) 异或矩阵 \(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\) 矩阵。
需要注意的是,一般情况下,乘法对异或没有分配律。例如对于 \(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\) 的值也不会改变,因此二者是相等的。
由此得到
同理,对于 \((A(BC))_{i, j}\) ,也可以写出式子后用同样的证明去括号,因此二者是相等的。在 \(C\) 是 \(01\) 矩阵时,矩阵异或具有结合律,可以进行快速幂。
因此有
这里 \(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;
}