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