标签:reg 根据 map cst += 结合 math zjoi 怎么
矩阵的乘法、快速幂
struct Matrix {
int s[51][51];
Matrix() { memset(s,0,sizeof(s)); }
int *operator [](int x) { return s[x]; }
}M;
Matrix operator *(Matrix a,Matrix b) { // 矩阵乘法
Matrix c;
for(int k=1; k<=n; ++k)
for(int i=1; i<=n; ++i)
if(a[i][k])
for(int j=1; j<=n; ++j)
if(b[k][j])
(c[i][j]+=a[i][k]*b[k][j])%=mo;
return c;
}
Matrix operator ^(Matrix a,int b) { // 矩阵快速幂
Matrix ans;
for(int i=1; i<=n; ++i) ans[i][i]=1;
for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a;
return ans;
}
https://www.luogu.org/problemnew/show/P2886
题目大意:给出一张无向连通图,求S到E经过k条边的最短路
如果我们有两个矩阵
其中一个矩阵代表恰好经过x条边的最短路
另一个矩阵代表恰好经过y条边的最短路
那么将这两个矩阵相结合就代表恰好经过x+y条边的最短路
$ c[i][j]=min(c[i][j],a[i][k]+b[k][j]); $
这道题是一个模型:邻接矩阵求经过k条边的最短路(简称k边最短路)
https://www.luogu.org/problemnew/show/P2579
首先不看食人鱼的情况
我们要求从s到t可以经过k条边(可以经过重复点)的方案数
这个是邻接矩阵运算最擅长的
与k边最短路不同的是
方案数是根据乘法原理得来的
所以我们在求解的时候要用到矩阵乘法
那么再把食人鱼放入到池塘里
发现食人鱼的周期奇短无比,都是12的因子
很小,所以我们可以构造出12个邻接矩阵。
利用这12个邻接矩阵
便既可以完全的表示出食人鱼的行动周期
也可以统计人活动的情况周期
就让食人鱼在某一时间点所在的地点情况数清零即可
然后以12为周期进行矩阵乘法
非常好的一道邻接矩阵的题目。
模型:求一个点到另一个点经过k条边的方案数(简称st-k方案数)
https://www.luogu.org/problemnew/show/P3758
这道题的构造巧妙无比
先不看有爆炸,可以停留的情况,这道题就变成了st-k方案数,只不过这里是从1出发,到1在内的所有节点的方案数
再来看可以停留这个条件。不就是从一个点走到自己吗?所以,再邻接矩阵中,我们只需要让一个点从自己连到自己就可以了。
爆炸怎么办?我们可以新开一个节点n+1,所有点向n+1连一条边,而它不向除自己以外的任何点连边。为什么n+1要向自己连边呢?这就像在一个点停留一样。如果不向自己连边,那么在下一个矩阵中它将不复存在。
这三道题都是十分经典的邻接矩阵运算题目
都有着非常好的价值和意义
可以说
如果完全掌握了这三道题
那么邻接矩阵的运算可以说是轻车熟驾了。
// luogu-judger-enable-o2
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define rg register int
#define ll long long
#define RG register
#define il inline
using namespace std;
il int gi() {
rg x=0,o=0;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
if(ch=='-') o=1,ch=getchar();
while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return o?-x:x;
}
#define SZ 2000001
int cnt,mp[SZ];
#define INF 2147483647
#define Getmin(a,b) (a)=(a)<(b)?(a):(b)
struct Matrix{ll a[201][201];};
Matrix dis,ans;
Matrix mul(Matrix a,Matrix b) {
Matrix c;
for(rg i=1; i<=cnt; ++i)
for(rg j=1; j<=cnt; ++j)
c.a[i][j]=INF;
for(rg k=1; k<=cnt; ++k)
for(rg i=1; i<=cnt; ++i)
for(rg j=1; j<=cnt; ++j)
Getmin(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
int n,m,s,t;
il void power(rg b) {
for(rg i=1; i<=cnt; ++i) ans.a[i][i]=0;
while(b) {
if(b&1) ans=mul(ans,dis);
dis=mul(dis,dis);
b>>=1;
}
}
int main() {
n=gi(),m=gi(),s=gi(),t=gi();
memset(mp,-1,sizeof(mp));
memset(ans.a,0x3f,sizeof(ans.a));
memset(dis.a,0x3f,sizeof(dis.a));
for(rg u,v,w,i=1; i<=m; ++i)
{
w=gi(),u=gi(),v=gi();
if(mp[u]==-1) mp[u]=++cnt;
if(mp[v]==-1) mp[v]=++cnt;
u=mp[u],v=mp[v];
Getmin(dis.a[u][v],w);
dis.a[v][u]=dis.a[u][v];
}
power(n);
printf("%lld",ans.a[mp[s]][mp[t]]);
return 0;
}
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define rg register int
#define ll long long
#define RG register
#define il inline
using namespace std;
il int gi() {
rg x=0,o=0;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
if(ch=='-') o=1,ch=getchar();
while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return o?-x:x;
}
int N,M,S,T,K,FN;
struct Matrix {
int s[51][51];
Matrix() {memset(s,0,sizeof(s));}
int *operator [](int x) {return s[x];}
}dis[13];
#define MOD 10000
Matrix operator *(Matrix a,Matrix b) {
Matrix c;
for(rg k=1; k<=N; ++k)
for(rg i=1; i<=N; ++i)
if(a[i][k])
for(rg j=1; j<=N; ++j)
if(b[k][j])
(c[i][j]+=a[i][k]*b[k][j])%=MOD;
return c;
}
Matrix operator ^(Matrix a,int b) {
Matrix ans;
for(rg i=1; i<=N; ++i) ans[i][i]=1;
for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a;
return ans;
}
int p[5];
int main() {
N=gi(),M=gi(),S=gi()+1,T=gi()+1,K=gi();
// 因为题目给出的是从 0 开始,所以我们要+1 来强制 从1开始
for(rg x,y,i=1; i<=M; ++i) {
x=gi()+1,y=gi()+1;
for(rg j=1; j<=12; ++j)
dis[j][x][y]=dis[j][y][x]=1;
}
FN=gi();
for(rg i=1; i<=FN; ++i) {
p[0]=gi();
for(rg j=1; j<=p[0]; ++j) p[j]=gi();
for(rg j=1; j<=12; ++j)
for(rg pos=j%p[0]+1,k=1; k<=N; ++k)
dis[j][k][p[pos]+1]=0;
}
for(rg i=1; i<=N; ++i) dis[0][i][i]=1;
for(rg i=1; i<=12; ++i) dis[0]=dis[0]*dis[i];
Matrix Ans=dis[0]^(K/12);
for(rg i=1; i<=K%12; ++i) Ans=Ans*dis[i];
printf("%d",Ans.s[S][T]);
return 0;
}
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define Getmax(a,b) (a)=(a)>(b)?(a):(b)
#define Getmin(a,b) (a)=(a)<(b)?(a):(b)
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define ll long long
#define gc getchar
using namespace std;
int gi() {
int x=0,o=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
if(ch=='-') o=1,ch=getchar();
while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return o?-x:x;
}
const int mo=2017;
int n,m;
struct Matrix {
int s[51][51];
Matrix() { memset(s,0,sizeof(s)); }
int *operator [](int x) { return s[x]; }
}M;
Matrix operator *(Matrix a,Matrix b) {
Matrix c;
for(int k=1; k<=n; ++k)
for(int i=1; i<=n; ++i)
if(a[i][k])
for(int j=1; j<=n; ++j)
if(b[k][j])
(c[i][j]+=a[i][k]*b[k][j])%=mo;
return c;
}
Matrix operator ^(Matrix a,int b) {
Matrix ans;
for(int i=1; i<=n; ++i) ans[i][i]=1;
for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a;
return ans;
}
int main() {
n=gi()+1,m=gi();
for(int i=1; i<=m; ++i) {
int u=gi(),v=gi();
M[u][v]=M[v][u]=1;
}
for(int i=1; i<=n; ++i) M[i][i]=1;
for(int i=1; i<=n-1; ++i) M[i][n]=1;
int t=gi(),ans=0;
M=M^t;
for(int i=1; i<=n; ++i) (ans+=M[1][i])%=mo;
printf("%d",ans);
return 0;
}
标签:reg 根据 map cst += 结合 math zjoi 怎么
原文地址:https://www.cnblogs.com/tply/p/9162263.html