codeforce 922 div 2 D

题目大意 一个数组,选一些数删除,求max(删除的数的和,除删除的数外连续子序列的和)

1 4 5 3 3 2

删除2 5位置上的数  max(4 + 3, 1 , 5 + 3, 2) = 8;

首先想到二分答案,第一个样例当x = 7 的时候正好满足,但是我们发现样例二,它答案是5,

1 2 3 4 5 如果按我们的思路当x = 5时 不满足,它在没有遍历后面的时候直接把 1 先删去了,需要优化check函数,所以现在我们需要动态规划的思想。

dp[i] 表示 删除第 i 个数 使前面全部满足的最小花费,

dp[i] = min(j ~ i , dp[j]) + a[i],(sum[j + 1, i - 1] <= x) 在连续子序列满足的情况下,求删除数的最小花费,如果花费小于x 返回true。

但是需要优化找最小的dp[j]的过程,所以需要使用优先队列来存一下每个满足条件的dp[i];

二分 + dp + 优先队列

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int t;
int n;
int dp[N];
int a[N];
typedef pair<int,int> pll;

bool check(int x)
{
    int sum = 0;
    int now = 0;
    int l = 1;
    priority_queue<pll, vector<pll>,greater<pll>> q;
    q.push({0 , 0});
    for(int r = 1;r <= n + 1;r ++){
        while(now > x){
            now -= a[l];
            l ++;
        }

        while(!q.empty() && q.top().second < l - 1)q.pop();
        dp[r] = q.top().first + a[r];
        q.push({dp[r] , r});
        now += a[r];
    }
    //for(int i = 1;i <= n + 1;i ++) cout << dp[i] << ' ';
    //cout << endl;
    return dp[n + 1] <= x;
}

void solve()
{
    cin >> n;
    for(int i = 1;i <= n;i ++) cin >> a[i];       
    a[n + 1] = 0;
    int l = 1,r = 1e14;
    while(l + 1 < r)
    {
        int mid = (l + r) / 2;
        if(check(mid))r = mid;
        else l = mid;
    }
    if(check(l))cout << l << endl;
    else cout << r << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while(t --)solve();
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谁能告诉我未来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值