题解:CF2110D Fewer Batteries
图上 DP + 二分答案
根据本题题意,通道为单向边且每条从点
根据这些条件可以确定本题的图是一张 DAG 图,呈现拓扑序,因而我们可以使用图上 DP 来做。
首先本题只需要关注电池数量,电池当前状态是否为充满电的条件其实根本没用,因为每次到达一个点时都直接给已拥有的所有电池充电了,即你拥有的电池永远是满电的。
并且容易发现你在移动的过程中拥有的电池数量单调不降,因为并没有给定 扔掉已拥有的电池 的操作。因而旅程结束时能够拥有的最少电池数量其实就取决于 从点
然后我们发现,若旅程结束时能够拥有的最少电池数量为
我们对
设
由于在二分答案
意味着只需要在走
那么初始化
那么我们判定一个
DP 转移方程:
因为你保证了移动的过程中不可能经过
同时为了避免
对于二分答案左端点
const 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;
}