Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4070
Solution
我们知道,有一个经典的建图优化:
在最短路等模型中,如果一个
个点的图要对于所有的
之间连边,边权为
,那么只需要将所有的
连双向边
,边权为
即可。
这道题里我们也可以用这样的思想:
对于所有的
,连有向边
,边权
。
但这样显然是不行的,为什么呢?
(1)复杂度不对(废话)
(2)举一例:一只 doge 在
位置,跳跃能力为
,另一只 doge 在
位置,跳跃能力为
,那么如果按照上面的思想建图,那么
位置的 doge 跳到
之后
位置的 doge 就能收到信息,这样显然是步星的。
于是我们要想办法把每只 doge 的路线独立起来。
取一个参数
,新建
个辅助点,分为
组,第
组表示跳跃能力为
。
对于第
组,有一对
则在第
组建双向边
,权值
;如果
号点初始有 doge 存在,那么连单向边从第
组的第
个点到原图第
个点,权值
。
如果跳跃能力大于
则暴力建边。
否则由原图中的
向第
组点内的
连权值为
的有向边。
建图完毕,由
开始跑单源最短路,到
的最短路为答案。
点数
,边数
(设
和
同阶)
取
时复杂度比较理想。
Code
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
using namespace std;
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 3e4 + 5, M = 303e4 + 5, L = 15e6 + 5, INF = 0x3f3f3f3f;
int n, m, B[N], P[N], ecnt, nxt[L], adj[M], go[L], val[L], S, dis[M];
bool vis[M];
queue<int> Q;
void add_edge(int u, int v, int w)
{
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
}
int which(int x, int y)
{
return x * n + y;
}
int SSSP()
{
memset(dis, INF, sizeof(dis));
dis[B[1]] = 0; Q.push(B[1]);
while (!Q.empty())
{
int u = Q.front(); Q.pop(); vis[u] = 0;
Edge(u)
if (dis[u] + val[e] < dis[v])
{
dis[v] = dis[u] + val[e];
if (!vis[v]) vis[v] = 1, Q.push(v);
}
}
return dis[B[2]];
}
int main()
{
int i, j, ans;
n = read(); m = read();
For (i, 1, m) B[i] = read() + 1, P[i] = read();
S = min((int) sqrt(n), 100);
For (i, 1, S) For (j, i + 1, n)
{
add_edge(which(i, j - i), which(i, j), 1);
add_edge(which(i, j), which(i, j - i), 1);
}
For (i, 1, S) For (j, 1, n)
add_edge(which(i, j), j, 0);
For (i, 1, m)
if (P[i] <= S)
add_edge(B[i], which(P[i], B[i]), 0);
else Step(j, (B[i] - 1) % P[i] + 1, n, P[i])
if (j != B[i])
add_edge(B[i], j, abs(B[i] - j) / P[i]);
if ((ans = SSSP()) == INF) puts("-1");
else cout << ans << endl;
return 0;
}