题解:P14681 [ICPC 2025 Yokohama R] Minimizing Wildlife Damage
题意:
给你
- 你可以选择任意的
A_i 让其变为0 。 -
Part1
首先理解清题意,为什么删去一些数可以让答案变大。
这是因为将一个数变为
Part2
考虑怎么删除才是最优秀的。稍微推导可以发现,除了一开始序列中的
所以对于每个前缀,都可以求出保留一些不相邻的
Part3
注意到操作完之后,我们的序列一定会分成三段,第一段全都被减成
显然第一段是
首先如果第三段没有被修改,那么它一定被一个
对于第二段,假设有连续很长一段大于
并且对于每个
所以从后往前,对于每个可行的第二段的开头,查询即可。然后将把这个位置改成
思路来自 jiangly
code:
struct Line{
__int128 k,b;
Line():k(0),b(0){}
Line(int _k,int _b):k(_k),b(_b){}
__int128 operator()(int x){
return k*x+b;
}
};
struct Node{
int ls,rs;
Line v;
}t[N];
int tot,root;
inline void insert(int &p,Line v,int L,int R){
if(!p)p=++tot;
int mid=(L+R)>>1;
if(t[p].v(mid)<v(mid)||!t[p].v.k)swap(t[p].v,v);
if(L==R||!v.k)return;
if(t[p].v(L)<v(L))insert(t[p].ls,v,L,mid);
if(t[p].v(R)<v(R))insert(t[p].rs,v,mid+1,R);
}
inline __int128 query(int p,int x,int L,int R){
if(!p)return -inf;
int mid=(L+R)>>1;
if(x<=mid)return max(t[p].v(x),query(t[p].ls,x,L,mid));
else return max(t[p].v(x),query(t[p].rs,x,mid+1,R));
}
int n,q;
int a[N],f[N];
int sum[N],ans[N],k[N];
pair<int,int>kval[N],val[N],fval[N];
vector<pair<int,int>>qry[N];
solve(){
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=q;i++){
cin>>k[i];
kval[i]=make_pair(k[i],i);
}
f[1]=a[1];
f[2]=a[2];
f[3]=a[1]+a[3];
for(int i=4;i<=n;i++)f[i]=max(f[i-2],f[i-3])+a[i];
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
f[i]-=a[i];
}
for(int i=1;i<=n;i++){
val[i]={f[i]+a[i],i};
fval[i]={f[i],i};
}
sort(kval+1,kval+q+1,greater<>());
sort(val+1,val+n+1,greater<>());
sort(fval+1,fval+n+1,greater<>());
set<int>S;
for(int i=1,j=0,t_=0;i<=q;i++){
if(kval[i].first==kval[i-1].first){
for(int x:S)qry[x].emplace_back(kval[i].first,kval[i].second);
continue;
}
while(j+1<=n&&val[j+1].first>kval[i].first)S.emplace(val[++j].second);
while(t_+1<=n&&fval[t_+1].first>kval[i].first)S.erase(fval[++t_].second);
for(int x:S)qry[x].emplace_back(kval[i].first,kval[i].second);
}
for(int i=n+1;i>=1;i--){
if(i<=n){
for(auto asd:qry[i]){
int k_=asd.first,id=asd.second;
__int128 res=query(root,f[i]-k_,-1e18,1e18);
res+=sum[n]-sum[i-1];
res+=__int128(k_)*i-__int128(f[i])*i;
ans[id]=max(ans[id],(int)res);
}
}
insert(root,Line(i,-a[i]),-1e18,1e18);
}
for(int i=1;i<=q;i++)cout<<ans[i]<<'\n';
return 0;
}