裁剪序列

给定一个长度为 N 的序列 A ,要求把该序列分成若干段,在满足“每段中所有数的和”不超过M的前提下,让“每段中所有数的最大值”之和最小。

试计算这个最小值。

输入格式
第一行包含两个整数N和M。

第二行包含N个整数,表示完整的序列A。

输出格式
输出一个整数,表示结果。

如果结果不存在,则输出-1。

数据范围
0≤N≤10^5,
0≤M≤10^11,
序列A中的数非负,且不超过10^6

输入样例:
8 17
2 2 2 8 1 8 2 1
输出样例:
12
#include<bits/stdc++.h>

#define ll long long
using namespace std;
const int N = 1e5 + 10;
ll f[N], m, sum;
int a[N], n;
deque<int> q;

int main() {
    scanf("%d%lld", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        if (a[i] > m) {
            puts("-1");
            return 0;
        }
    }
    for (int i = 1, j = 0; i <= n; i++) {
        sum += a[i];
        while (sum > m)sum -= a[++j];
        while (!q.empty() && q.front() <= j)q.pop_front();
        while (!q.empty() && a[q.back()] <= a[i])q.pop_back();
        q.push_back(i);
        f[i] = f[j] + a[q.front()];
        auto en = --q.end();
        for (auto it = q.begin(); it != en;)
            f[i] = min(f[i], f[*it] + a[*(++it)]);
    }
    printf("%lld\n", f[n]);
    return 0;
}

优化版

#include<bits/stdc++.h>

#define ll long long
using namespace std;
const int N = 1e5 + 10;
ll f[N], m, sum;
int a[N], n;
deque<int> q;
multiset<ll> heap;
multiset<ll>::iterator it;

int main() {
    scanf("%d%lld", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        if (a[i] > m) {
            puts("-1");
            return 0;
        }
    }
    for (int i = 1, j = 0; i <= n; i++) {
        sum += a[i];
        while (sum > m)sum -= a[++j];
        while (!q.empty() && q.front() <= j) {
            if (q.size() > 1 && (it = heap.find(f[q.front()] + a[*(++q.begin())])) != heap.end())
                heap.erase(it);
            q.pop_front();
        }
        while (!q.empty() && a[q.back()] <= a[i]) {
            if (q.size() > 1 && (it = heap.find(f[*(-- --q.end())] + a[q.back()])) != heap.end())
                heap.erase(it);
            q.pop_back();
        }
        if (!q.empty())heap.insert(f[q.back()] + a[i]);
        q.push_back(i);
        f[i] = f[j] + a[q.front()];
        if (!heap.empty())f[i] = min(f[i], *heap.begin());
    }
    printf("%lld\n", f[n]);
    return 0;
}
发布了329 篇原创文章 · 获赞 28 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45323960/article/details/105003087