题解 P5107 【能量采集】
P5107 能量采集
传送门
暴 力 草 标 算
当然也不是最基础的暴力,用矩阵快速幂倍增一下再卡卡常就轻松过去了。
前置知识
先看数据范围,$1\leqslant n\leqslant 50$,显然是让 $n^3$ 算法过的, $n^3$ 想到什么?矩阵乘法!
想到矩阵乘法就好做了,如果你不知道矩阵乘法是什么那你看为啥要看这道题,出门左转模板区矩阵快速幂和矩阵加速,这里简单列出式子,不再讲解:
对于 $p\times q$ 的矩阵 $A$ 与 $q\times r$ 的矩阵 $B$,它们的乘积 $C=A\times B$ 计算方式为:
$$C_{i,j}=\sum_{k=1}^{q}A_{i,k}\times B_{k,j}$$
时间复杂度为 $O(pqr)$。
现在你了解了矩阵乘法与矩阵快速幂,那么对于这道题,我们可以使一个 $n\times1$ 的矩阵 $res$ 为初始矩阵,其中 $res_{i,1}$ 代表第 $i$ 个点最开始的能量。
对于边,我们创造一个 $n\times n$ 的转换矩阵 $base$ 为图的邻接矩阵,其中,$res_{i,1}\times base_{i,j}$ 为 $i$ 号点会流给 $j$ 号点的能量。对于边$(u,v)$,我们使 $base'_{v,u}$ 加一,最后$$base_{i,j}=\frac{base'_{i,j}}{\sum_{k=1}^nbase'_{k,j}}$$
求一个逆元即可。
对于每次询问直接上矩阵快速幂吗?时间复杂度为 $O(qn^3log_2t)≈1.8\times10^{11}$ 原地升天。
那怎么办?
令$$P_i=base^{2^i}={P_{i-1}}^2$$ 每次询问的答案矩阵 $ans$ 初始值设为 $res$ ,对于每个 $i\in[0,31]$ 且 $t$ 在二进制下第 $i$ 位有为 $1$,$ans\gets P_i\times ans$ .
最终答案为$\bigoplus_{i=1}^{n}ans_{i,1}$。
时间复杂度为$O(n^3log_2t+qn^2log_2t)≈3.7\times10^9$,卡卡常就可以过了,用__int128把 $\sum_{k=1}^{q}A_{i,k}\times B_{k,j}$ 存起来最后取模可以大大减少取模次数,可以卡进 $3s$。
正解大概是转到 $k$ 进制倍增,但是我太蒟蒻了不会,可以看别的奆佬的题解。
$Code$:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//IO优化
int len=0;
char ibuf[(1<<20)+1],*iS,*iT,out[(1<<25)+1];
#define gh() (iS==iT?iT=(iS=ibuf)+fread(ibuf,1,(1<<20)+1,stdin),(iS==iT?EOF:*iS++):*iS++)
#define reg register
inline int read(){
reg char ch=gh();
reg int x=0;
while(ch<'0'||ch>'9') ch=gh();
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=gh();
return x;
}
inline void write(int x){
if(x>9)write(x/10);
out[len++]=x%10+48;
}
}using namespace IO;
const int mod=998244353;
inline void add(int &a,int b){//优化加法
a+=b;
if(a>=mod) a-=mod;
}
struct matrix{//矩阵
int n,m,a[55][55];
int* operator[](const int &x){
return a[x];
}
matrix(){
memset(a,0,sizeof(a));
}
friend matrix operator*(const matrix &a,const matrix &b){//矩阵乘法
matrix c;
c.n=a.n;
c.m=b.m;
for(int i=1;i<=a.n;i++){
for(int j=1;j<=b.m;j++){
__int128 ret=0;
for(int k=1;k<=a.m;k++){
ret+=1ll*a.a[i][k]*b.a[k][j];
}
c[i][j]=ret%mod;
}
}
return c;
}
inline void init(int qwq){//大小为qwq*qwq的单位矩阵
n=m=qwq;
for(int i=1;i<=n;i++){
a[i][i]=1;
}
}
}res,p[32];
inline int qpow(int x,int y){//快速幂
int ret=1;
while(y){
if(y&1) ret=1ll*ret*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return ret;
}
int n,m,q;
inline void init(){
n=read(),m=read(),q=read();
for(int i=1;i<=n;i++){//原矩阵
res[i][1]=read();
}
res.n=n;
res.m=1;
p[0].init(n);
for(int i=1;i<=m;i++){
int u=read(),v=read();
p[0][v][u]++;//邻接矩阵
}
for(int i=1;i<=n;i++){
int ret=0;
for(int j=1;j<=n;j++){
add(ret,p[0][j][i]);
}
ret=qpow(ret,mod-2);//逆元
for(int j=1;j<=n;j++){
p[0][j][i]=1ll*p[0][j][i]*ret%mod;
}
}
for(int i=1;i<=31;i++){//预处理P
p[i]=p[i-1]*p[i-1];
}
}
inline void solve(){
for(int i=1;i<=q;i++){
int t=read();
matrix now=res;
for(int j=31;~j;j--){//倍增
if(t&(1<<j)){
now=p[j]*now;
}
}
ll ans=0;
for(int j=1;j<=n;j++){
ans^=now[j][1];
}
write(ans%mod);
out[len++]='\n';
}
}
int main(){
init();
solve();
fwrite(out,1,len,stdout);
return 0;
}
/*
Memoty:5.49MB
Time:5.17s
*/
那么蒟蒻的这篇题解就结束了,再见$qwq$~

浙公网安备 33010602011771号