目录
[D. Bonus EXP](#D. Bonus EXP)
[E. Sightseeing Tour](#E. Sightseeing Tour)
D. Bonus EXP
常规思路是 dp [ i ] 表示到前 i 个怪的最大收益值,因为要看奇偶性所以再加一维,0 表示当前这个怪打或不打共打了偶偶数怪,1 表示打
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
int T, n, cnt, ans, a[N], dp[N][2];
string s;
signed main()
{
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> a[i];
dp[1][0] = 0, dp[1][1] = a[1];
for (int i = 2; i <= n; i ++)
{
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + 2 * a[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + a[i]);
}
ans = max(dp[n][0], dp[n][1]);
cout << ans;
return 0;
}
E. Sightseeing Tour
n 小于 400,可以先 floyd 求出两两之间的最短路。对于必走的 k 条边,先全排列,同时要考虑双向。答案就是 k 条边内部的累积和加上 1 到全排列的第一个的起点加上全排列最后一个的终点到 n 的最短路。
在 floyd 前要有两次初始化,一次是自己到自己置为 0,其余 INF,一次是存在边的两点赋初值。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, INF = 1e18;
struct node
{
int u, v, w;
}e[N];
int T, n, m, q, cnt, ans, a[405], f[405][405], vis[10];
void dfs(int u, int pos, int tot, int k)
{
if(pos > k)
{
tot += f[u][n];
ans = min(ans, tot);
return;
}
for (int i = 1; i <= k; i ++)
{
if (vis[i] == 1)
continue;
vis[i] = 1;
int d = f[u][e[a[i]].u] + e[a[i]].w;
dfs(e[a[i]].v, pos + 1, tot + d, k);
d = f[u][e[a[i]].v] + e[a[i]].w;
dfs(e[a[i]].u, pos + 1, tot + d, k);
vis[i] = 0;
}
}
signed main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
f[i][j] = i == j ? 0 : INF;
for (int i = 1; i <= m; i ++)
{
cin >> e[i].u >> e[i].v >> e[i].w;
f[e[i].u][e[i].v] = min(f[e[i].u][e[i].v], e[i].w), f[e[i].v][e[i].u] = min(f[e[i].v][e[i].u], e[i].w);
}
for (int k = 1; k <= n; k ++)
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
cin >> q;
while (q --)
{
int k;
cin >> k;
ans = INF;
for (int i = 1; i <= k; i ++)
cin >> a[i];
for (int i = 1; i <= k;i ++)
vis[i] = 0;
dfs(1, 1, 0, k);
cout << ans << '\n';
}
return 0;
}