1. 程式人生 > 實用技巧 >LG P6569 [NOI Online #3 提高組]魔法值

LG P6569 [NOI Online #3 提高組]魔法值

Description

H 國的交通由 $n$ 座城市與 $m$ 條道路構成,城市與道路都從 $1$ 開始編號,其中 $1$ 號城市是 H 國的首都。H 國中一條道路將把兩個不同城市直接相連,且任意兩個城市間至多有一條道路。

H 國是一個信奉魔法的國家,在第 $j$ 天,$i$ 號城市的魔法值為 $f_{i,j}$。H 國的魔法師已觀測到第 0 天時所有城市的魔法值 $f_{i,0}$,且他們還發現,之後的每一天每個城市的魔法值,都將會變為所有與該城市直接相連的城市的前一天魔法值的異或值,即

$$
f_{x,j}=f_{v_1,j-1}\oplus f_{v_2,j-1}\oplus \cdots\oplus f_{v_k,j-1}
$$

其中 $j\ge 1$,$v_1,v_2,\cdots,v_k$ 是所有與 $x$ 號城市直接相連的城市,$\oplus$ 為異或運算。

現在 H 國的國王問了你 $q$ 個問題,對於第 $i$($1\le i\le q$)個問題你需要回答:第 $a_i$ 天時首都的魔法值是多少。

Solution

可以發現答案就是給出的陣列乘上鄰接矩陣的$a_i$次方,直接做會得到40分

如果預處理$2$的冪次的鄰接矩陣,每次詢問時使用倍增,可以將時間複雜度中一個$n$壓縮到$\log n$

#include<iostream>
#include<cstring>
#include
<cstdio> using namespace std; int n,m,q; long long temp[105]; struct Matrix { int x,y; long long a[105][105]; Matrix operator * (const Matrix &z)const { Matrix ret; memset(ret.a,0,sizeof(ret.a)),ret.x=x,ret.y=z.y; for(int i=1;i<=x;i++) for(int j=1
;j<=z.y;j++) for(int k=1;k<=y;k++) ret.a[i][j]^=1ll*a[i][k]*z.a[k][j]; return ret; } void print() { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cout<<a[i][j]<<" "; } cout<<endl; } } }F,G[50]; inline long long read() { long long f=1,w=0; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return f*w; } int main() { //freopen("data.txt","r",stdin); //freopen("my.out","w",stdout); n=read(),m=read(),q=read(); for(int i=1;i<=n;i++) temp[i]=read(); F.x=1,F.y=G[0].x=G[0].y=n; for(int i=1;i<=m;i++) { int u=read(),v=read(); G[0].a[u][v]=G[0].a[v][u]=1ll; } for(int i=1;i<=31;i++) G[i]=G[i-1]*G[i-1]; for(int i=1;i<=q;i++) { int A=read(); for(int j=1;j<=n;j++) F.a[1][j]=temp[j]; for(int j=0;j<=31;j++) if(A&(1<<j)) F=F*G[j]; printf("%lld\n",F.a[1][1]); } return 0; }
魔法值