题面
牛牛所在的W市是一个不太大的城市,城市有n个路口以及m条公路,这些双向连通的公路长度均为1。牛牛在玩宝可梦Go,众所周知呢,这个游戏需要到城市的各个地方去抓宝可梦,假设现在牛牛知道了接下来将会刷出k只宝可梦,他还知道每只宝可梦的刷新时刻、地点以及该宝可梦的战斗力,如果在宝可梦刷新时,牛牛恰好在那个路口,他就一定能够抓住那只宝可梦。
由于游戏公司不想让有选择恐惧症的玩家为难,所以他们设计不存在任何一个时刻同时刷出两只及以上的宝可梦。
假设不存在任何一个时刻会同时刷出两只宝可梦,牛牛一开始在城市的1号路口,最开始的时刻为0时刻,牛牛可以在每个时刻之前移动到相邻他所在位置的路口,当然他也可以保持原地不动,他现在想知道他能够捕获的宝可梦战斗力之和最大为多少?
样例一
3 2
1 2
2 3
3
1 1 5
2 3 10
3 2 1
11
样例二
1 0
3
1 1 100
100 1 10000
10000 1 1
10101
样例三
3 2
1 2
2 3
1
1 3 1000000000
0
样例四
3 2
1 2
2 3
1
1 2 1000000000
1000000000
首先,关于求解任意两点之间的最短路,是为了求解出任意两点之间相互达到所需要的最小花费时间。
然后的话,这里有个剪枝,除去剪枝的话,复杂度优化一点可以达到的是,这个复杂度是怎样来的呢?就是我们去求维护一个dp[点][时刻],然后我们每次因为只会更新一个点,所以我们可以去枚举N个点,包括自己,因为可以待着不动,我们用log的方法(二分查询)查询前面哪一个时刻可以转移到目前时刻,这是复杂度为的写法了。
其实会发现,这里有可以剪枝的部分,剪枝之后的复杂度会变成,或者说是,因为图的最大的大小就是200,所以图的直径最长也不过是199,方便写,我们写到200,于是乎,200以上的距离我们可以任意到达,那么同样的,距当前询问有200次询问之前的询问,我们可以直接继承,所以这里可以维护一个前缀最大值。然后,我们每次只需要去看前1~200次中的询问,是否可以得到,以及跟最大值的比较,然后是更新答案。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define IINF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e2 + 7;
int N, M, K, head[maxN], cnt, mp[maxN][maxN], t[maxN];
ll dp[100005] = {0}, ans = 0;
inline void floyd()
{
for(int k=1; k<=N; k++)
{
for(int j=1; j<=N; j++)
{
for(int i=1; i<=N; i++)
{
if(i == j) continue;
mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
}
}
}
}
struct node
{
int t, p; ll val;
node(int a=0, int b=0, ll c=0):t(a), p(b), val(c) {}
inline void In_Put() { scanf("%d%d%lld", &t, &p, &val); }
friend bool operator < (node e1, node e2) { return e1.t < e2.t; }
}op[100005];
int Lsan[100005];
int main()
{
scanf("%d%d", &N, &M);
for(int i=1; i<=N; i++)
{
for(int j=1; j<=N; j++) mp[i][j] = INF;
mp[i][i] = 0;
}
for(int i=1, u, v; i<=M; i++)
{
scanf("%d%d", &u, &v);
mp[u][v] = mp[v][u] = 1;
}
floyd();
scanf("%d", &K);
for(int i=1; i<=K; i++)
{
op[i].In_Put();
Lsan[i] = op[i].t;
}
sort(Lsan + 1, Lsan + K + 1);
sort(op + 1, op + K + 1);
op[0] = node(0, 1, 0);
ll pre_max = 0;
for(int i=1; i<=K; i++)
{
if(i > 200)
{
pre_max = max(pre_max, dp[i - 200]);
dp[i] = op[i].val + pre_max;
}
else
{
dp[i] = -IINF;
}
for(int j=1; j<=200 && i - j >= 0; j++)
{
if(op[i].t - op[i - j].t >= mp[op[i].p][op[i - j].p])
{
dp[i] = max(dp[i], dp[i - j] + op[i].val);
}
}
ans = max(ans, dp[i]);
}
printf("%lld\n", ans);
return 0;
}