专栏文章
题解:CF2110D Fewer Batteries
CF2110D题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @minz21e1
- 此快照首次捕获于
- 2025/12/02 10:41 3 个月前
- 此快照最后确认于
- 2025/12/02 10:41 3 个月前
图上 DP + 二分答案
根据本题题意,通道为单向边且每条从点 移动到点 的通道满足 。
根据这些条件可以确定本题的图是一张 DAG 图,呈现拓扑序,因而我们可以使用图上 DP 来做。
首先本题只需要关注电池数量,电池当前状态是否为充满电的条件其实根本没用,因为每次到达一个点时都直接给已拥有的所有电池充电了,即你拥有的电池永远是满电的。
并且容易发现你在移动的过程中拥有的电池数量单调不降,因为并没有给定 扔掉已拥有的电池 的操作。因而旅程结束时能够拥有的最少电池数量其实就取决于 从点 到点 的所有路径中经过的边权最大值的最小值,并且你要保证过程中你是可以经过那条边的(即对于 的边 而言,你要保证到达 时拥有的电池数量 + 在 点取到的电池数量 )。
然后我们发现,若旅程结束时能够拥有的最少电池数量为 ,说明拥有 个电池能够使得我们从起点 到终点 ,而对于拥有 个电池时一定也能从起点 到终点 。证明了答案具有单调性,因而可以考虑二分答案来确定这个满足条件的最小的 。
我们对 进行二分答案,其中 表示整个过程中拥有的电池数量不会超过 ,也就是说你移动的过程中不可能经过边权 的边。
设 表示表示从点 出发且刚到达 点且还没获取时 位置的能量时拥有的电池数量的最大值(因为要使拥有的能量尽可能小,自然是考虑离开这个位置时才尝试获取该位置能量,即非必要不取该位置的能量)。
由于在二分答案 时,我们是考虑在旅程全程中拥有的最少电池数量不超过 的情况下能否从点 到达点 。
意味着只需要在走 的边权下 处能否可达,只需要考虑最极端最贪的情况即可,即应让 数组尽可能取大,由于使用二分求最小了,因而正确性是保证的。
那么初始化 ,。
那么我们判定一个 是否可行即判定在当前这个 下 是否成立。
DP 转移方程:
因为你保证了移动的过程中不可能经过 的边,即能发生 DP 转移时已经保证了 。
同时为了避免 可能超过 ,于是两者取一个最小值即可。
对于二分答案左端点 ,右端点 (用于无解判定),若最终二分的结果为 ,说明无解。
CPPconst int N=2e5+5;
int n,m;
int power[N];
vector<array<int,2> > E[N];
int f[N]; // f[u] 表示刚到达 u 点且还没获取该位置能量的最大值(考虑离开这个位置时才尝试获取该位置能量)
bool check(int x){
int INF;
memset(&INF,0x3f,sizeof INF);
rep(i,1,n) f[i]=-INF;
f[1]=0;
rep(u,1,n){
for(auto t:E[u]){
int v=t[0],w=t[1];
if(w>x) continue;
if(f[u]+power[u]>=w){
f[v]=max(f[v],min(x,f[u]+power[u]));
}
}
}
return f[n]>=0;
// rep(i,1,n) cout<<f[i]<<" ";
// cout<<endl;
}
void solve(){
cin>>n>>m;
rep(i,1,n) E[i].clear();
rep(i,1,n) cin>>power[i];
rep(i,1,m){
int a,b,c;
cin>>a>>b>>c;
E[a].push_back({b,c});
}
int l=0,r=1e9+1;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
if(r==1e9+1) cout<<-1;
else cout<<l;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...