luoguP6569 [NOI Online #3 提高组]魔法值 矩阵乘法+倍增
朴素的矩阵乘法时间复杂度会爆炸,但是我们发现矩阵乘法的形式是一个 $(1 \times n) \times (n \times n)$ 的形式.
所以如果提前预处理出来 $(n \times n)$ 矩阵的 $2^i$ 次幂,然后每次询问的时候二进制拆分,复杂度就是 $O(n^2 \log 1e9)$ 的.
code:
#include <bits/stdc++.h> #define N 105 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; ll f[N],arr[N],brr[N]; int n,m,q; struct M { ll ma[N][N]; M() { memset(ma,0,sizeof(ma)); } ll *operator[](int x) { return ma[x]; } M operator*(const M b) const { M c; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) for(int k=1;k<=n;++k) c.ma[i][j]^=ma[i][k]*b.ma[k][j]; return c; } }mat[42],g; int main() { // setIO("input"); int x,y,z; scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;++i) scanf("%lld",&f[i]); for(int i=1;i<=m;++i) scanf("%d%d",&x,&y),g[x][y]=g[y][x]=1; mat[0]=g; for(int i=1;i<40;++i) mat[i]=mat[i-1]*mat[i-1]; for(int i=1;i<=q;++i) { scanf("%d",&x); for(int j=1;j<=n;++j) arr[j]=f[j]; for(int j=0;j<32;++j) { if(x&(1<<j)) { for(int k=1;k<=n;++k) brr[k]=0; for(int k=1;k<=n;++k) for(int t=1;t<=n;++t) brr[k]^=arr[t]*mat[j][t][k]; for(int k=1;k<=n;++k) arr[k]=brr[k]; } } printf("%lld\n",arr[1]); } return 0; }