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

  

posted @ 2020-06-10 10:02  EM-LGH  阅读(231)  评论(0编辑  收藏  举报