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;
}

浙公网安备 33010602011771号