CF2023B/CF2024D-Skipping-题解
CF2023B/CF2024D
题意分析
首先我们可以发现,在第 $i$ 个点上时,所得的得分为从 $1$ 到 $i$ 之和减去跳过的问题。所以此题可以转化为求跳过的题目的最小值。所以答案就是
$$ans=\max_{i=1}^{n}(sum_i-dis_i)$$
其中的 $sum_i$ 表示从 $1$ 到 $i$ 的前缀和,$dis_i$ 表示从 $1$ 到 $i$ 的代价最小值。
关于如何求 $dis_i$,我们可以建图跑最短路,对 $i\rightarrow i-1$ 建边,权值为 $0$,对 $i\rightarrow b_i$ 建边,权值为 $a_i$。之后通过最短路求出 $dis_i$,然后枚举答案即可。
Code
#pragma GCC optimize(1, 2, 3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
#define ONLINE_JUDGE
#define MULTI_CASES
#define endl '\n'
const int MaxN = 4e5+100;
const int INF = 1e15;
const int mod=212370440130137957ll;
int T=1, N, M;
// int dis[MaxN];
vector<pair<int,int>>G1[MaxN];
struct Dijkstra{
int d[MaxN], vis[MaxN];
struct Point {
int id, x;
inline bool operator<(const Point &aa)const {
return x > aa.x;
}
};
priority_queue<Point>q;
inline void solve(int S) {
for(int i = 1; i <= N; i++) d[i] = INF, vis[i] = 0;
d[S] = 0;
q.push((Point){ S, 0 });
while(!q.empty()) {
auto [x, w] = q.top(); q.pop();
if (vis[x]) continue;
vis[x] = 1;
for(auto it : G1[x]) {
int y = it.first;
int z = it.second;
if(d[x] + z < d[y]) {
d[y] = d[x] + z;
if(!vis[y]) q.push((Point){ y, d[y] });
}
}
}
}
};
inline void Solve()
{
cin>>N;
// vector<pair<int,int>> G1[MaxN];
vector<int>sum(N+1);
vector<int>a(N+1);
for(int i=1;i<=N;i++){
cin>>a[i];
sum[i]=sum[i-1]+a[i];
if(i!=1)
G1[i+1].push_back(make_pair(i,0));
}
for(int i=1;i<=N;i++){
int x;
cin>>x;
G1[i].push_back(make_pair(x,a[i]));
}
Dijkstra dij;
dij.solve(1);
int ans=0;
for(int i=1;i<=N;i++){
// cout<<dij.d[i]<<" ";
ans=max(ans,sum[i]-dij.d[i]);
G1[i].resize(0);
}
cout<<ans<<endl;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
#ifdef MULTI_CASES
cin >> T;
while (T--)
#endif
Solve();
//fclose(stdin);
//fclose(stdout);
return 0;
} 本文采用 CC BY-NC 4.0 许可协议,转载请注明出处并保持非商业用途。