n<=100,很明顯矩陣存儲圖,設原圖爲A(n*n),每次fi都是前i-1轉移而來,f[i]=W(1*n)*A^i也就是長度爲i的邊所影響的節點。
圖上可達矩陣普通乘法是 意義:(aij)^k代表ij路徑長度爲k的條數。
本題爲異或W(1*n)^(A運算A.....),這個運算是什麼運算呢?和普通矩陣乘法有什麼區別?
ai*j代表有aij個wi相異或。根據異或運算的規則,偶數個形同的數異或相當於沒有參與運算。因此可以普通矩陣運算再算奇偶性,也可以如果進行普通矩陣運算,注意數據範圍,數據值將會很大。或者直接進行矩陣上的異或運算。
將每次的矩陣進行倍增後存儲,備用。
對每個詢問,進行矩陣快速冪運算,時間複雜度爲n*n*n*logn,總時間複雜是爲q*n*n*n*logn,只能得40分,還是超時。
因爲W爲1*n的矩陣,先進行w*A的運算,時間複雜度爲n*n,總複雜度變爲q*n*n*logn
參考代碼:
#include<bits/stdc++.h>
using namespace std;
const int N=110;
typedef long long ll;
ll w[N], A[35][N][N],dp[N][N];
ll n,m,q,u,v;
ll work(ll x) {
ll ans=0;
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)dp[i][i]=1;
for(int l=0; l<=31&&x; l++) {
if(x&(1ll<<l)) {
ll tmp[N][N]= {0};
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int k=1; k<=n; k++) {
tmp[i][j]^=dp[i][k]*A[l][k][j];
}
memcpy(dp,tmp,sizeof(tmp));
x-=(1<<l);
}
}
for(int i=1; i<=n; i++)if(dp[i][1])ans=ans^w[i];
return ans;
}
int main() {
scanf("%lld%lld%lld",&n,&m,&q);
for(int i=1; i<=n; i++)scanf("%lld",&w[i]);
for(int i=1; i<=m; i++) {
scanf("%lld%lld",&u,&v);
A[0][u][v]=A[0][v][u]=1;
}
for(int l=1; l<=31; l++) { //倍增2^l,求出路徑長度爲2^l的路徑條數
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int k=1; k<=n; k++)
A[l][i][j]^=A[l-1][i][k]*A[l-1][k][j];
}
for(int i=1; i<=q; i++) {
ll x;
scanf("%lld",&x);
printf("%lld\n",work(x));
}
return 0;
}