D. Blocking Elements

原题链接

题解

最大值最小化,想到了二分
而对于一个二分到的 \(\mathscr{maxlen}\) 而言,如何判断是否存在一种分法使得最大值不大于它?

对于一个给定的二分值而言,要想成功有两个约束条件,一个是间断值不超过 \(\mathscr{maxlen}\) ,一个是选中值之和不超过 \(\mathscr{maxlen}\)

由此我们让第一个条件作为约束条件来寻找第二个条件是否成立
这里太巧妙了!!!!
\(dp[i]\) 为选中 \(i\) ,且 \(i\) 之前的间断值都不超过 \(maxlen\) 的最小值
\(dp[i]\) 是由前面间断值不大于 \(maxlen\) 的最小的 \(dp[i]\) 转移而来的
然后判断 \(dp[n+1]\) 有没有大于 \(maxlen\)

真的太巧妙了!!!

code

···

include<bits/stdc++.h>

define ll long long

using namespace std;

ll n;
ll a[100005]={0};
ll pres[100005]={0};
ll dp[100005]={0};
struct node
{
ll x;
bool operator<(const node &b) const{return dp[x]>dp[b.x];}
};
ll check(ll maxlen)
{

priority_queue<node> q;
q.push({0});
a[n+1]=0;
for(ll i=1;i<=n+1;i++)
{
    while(q.size()&&pres[i-1]-pres[q.top().x]>maxlen) q.pop();
    ll x=q.top().x;
    dp[i]=dp[x]+a[i];
    q.push({i});
}
if(dp[n+1]>maxlen)  return 0;
return 1;

}
int main()
{
ll t;
cin>>t;
while(t--)
{
cin>>n;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
pres[i]=pres[i-1]+a[i];
}

    ll l=0,r=pres[n];
    while(l+1<r)
    {
        ll mid=(l+r)/2;
        if(check(mid))r=mid;
        else l=mid;
    }

    cout<<r<<endl;
}
return 0;

}

···

posted @ 2024-03-15 16:42  纯粹的  阅读(17)  评论(0)    收藏  举报