题面传送门
其实
n
n
n可以开到
1
e
18
1e18
1e18
显然可以倍增
f
l
o
y
d
floyd
floyd
直接把矩阵乘法的乘改成加单位矩阵也改一下变成
a
i
,
j
=
min
k
=
1
n
b
i
,
k
+
c
k
,
j
a_{i,j}=\min\limits_{k=1}^{n}{b_{i,k}+c_{k,j}}
ai,j=k=1minnbi,k+ck,j即可。
然后就是矩阵快速幂板子。
时间复杂度
O
(
m
3
l
o
g
n
)
O(m^3logn)
O(m3logn)
注意离散
代码实现:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,s,t,a[239][239],b[239][239],c[239][239],x[139],y[139],z[139],nows[239],tots[239],l,r,mid;
int main() {
register int i,j,k;
memset(a,0x3f,sizeof(a));
memset(c,0x3f,sizeof(c));
scanf("%d%d%d%d",&n,&m,&s,&t);
for(i=1; i<=m; i++) scanf("%d%d%d",&z[i],&x[i],&y[i]),nows[2*i-1]=x[i],nows[i*2]=y[i];
nows[2*m+1]=s,nows[2*m+2]=t;
sort(nows+1,nows+2*m+3);
for(i=1; i<=2*m+2; i++) {
tots[i]=tots[i-1];
if(nows[i]!=nows[i-1]) tots[i]++;
}
for(i=1; i<=m; i++) {
l=0;
r=2*m+3;
while(l+1<r) {
mid=(l+r)>>1;
if(nows[mid]<x[i]) l=mid;
else r=mid;
}
x[i]=tots[r];
l=0;
r=2*m+3;
while(l+1<r) {
mid=(l+r)>>1;
if(nows[mid]<y[i]) l=mid;
else r=mid;
}
y[i]=tots[r];
a[x[i]][y[i]]=a[y[i]][x[i]]=z[i];
}
l=0;
r=2*m+3;
while(l+1<r) {
mid=(l+r)>>1;
if(nows[mid]<s) l=mid;
else r=mid;
}
s=tots[r];
l=0;
r=2*m+3;
while(l+1<r) {
mid=(l+r)>>1;
if(nows[mid]<t) l=mid;
else r=mid;
}
t=tots[r];
for(i=1;i<=tots[2*m+2];i++) c[i][i]=0;
while(n) {
if(n&1) {
memset(b,0x3f,sizeof(b));
for(i=1; i<=tots[2*m+2]; i++) {
for(j=1; j<=tots[2*m+2]; j++) {
for(k=1; k<=tots[2*m+2]; k++) b[i][j]=min(b[i][j],a[i][k]+c[k][j]);
}
}
for(i=1; i<=tots[2*m+2];i++) {
for(j=1; j<=tots[2*m+2]; j++) c[i][j]=b[i][j];
}
}
memset(b,0x3f,sizeof(b));
for(i=1; i<=tots[2*m+2]; i++) {
for(j=1; j<=tots[2*m+2]; j++) {
for(k=1; k<=tots[2*m+2]; k++) b[i][j]=min(b[i][j],a[i][k]+a[k][j]);
}
}
for(i=1; i<=tots[2*m+2];i++) {
for(j=1; j<=tots[2*m+2]; j++) a[i][j]=b[i][j];
}
n>>=1;
}
printf("%d\n",c[s][t]);
}