cf div3 E2. Array and Segments (选区间进行-1,使数组差值最大)

该博客讨论了一道编程题,题目要求在给定数组中选择多个区间,每次操作区间内所有元素减1,目标是找到一种选择方式使得数组元素差值(最大值减最小值)达到最大。解题策略包括离散化和分块处理,特别注意处理区间长度为1的情况,防止在离散化过程中丢失这种特殊区间。
摘要由CSDN通过智能技术生成

题目链接

给一个长度为n的数组,和m个区间。

每当你选择一个区间,数组中该区间内的数值全部减1,每个区间最多选一次。

问数组内元素的差值(最大值-最小值)最大是多少。

 

注意事项:

离散化分块。

这里离散化遇到了问题,假如某个区间的左右端点相同(长度为1),那么去重时会把该区间删除掉。

所以,可以将题目给定的 [l,r] 改为 [l,r+1) 再进行离散化。

 

#include <bits/stdc++.h>
#define pii pair<int,int>
#define fir first
#define sec second
using namespace std;
const int N = 1e5+100;
const int M = 500;
struct node{
    int maxx,minn;
}s[3*M],s2[3*M];
int a[N];
pii seg[M];
int main() {
    //freopen("a.txt","r",stdin);
    ios::sync_with_stdio(0);
    int n,m;
    cin>>n>>m;
    for(int i = 1; i <= n; i++) cin>>a[i];
    vector<int> k;
    for(int i = 1; i <= m; i++) {       //离散化
        int l,r;
        cin>>l>>r;
        r++;
        seg[i].fir = l;
        seg[i].sec = r;
        k.push_back(l);
        k.push_back(r);
    }
    k.push_back(1);             
    k.push_back(n+1);           
    sort(k.begin(),k.end());
    k.erase(unique(k.begin(),k.end()),k.end());
    
    
    for(int i = 0; i < k.size()-1; i++) {   //记录每个块的最大值和最小值
        int maxx = -1e9;
        int minn = 1e9;
        for(int j = k[i]; j < k[i+1]; j++) {
            maxx = max(maxx,a[j]);
            minn = min(minn,a[j]);
        }
        s[i].maxx = maxx;
        s[i].minn = minn;
    }
    
    int tot = k.size();
    for(int i = 0; i < tot+10;i ++) s2[i] = s[i];
    int ans = 0;
    vector<int>need;
    for(int i = 0; i < k.size()-1; i++) {               //枚举答案的最小值在哪个块内
        vector<int>p;
        for(int j = 0; j < tot+10;j ++) s[j] = s2[j];
        for(int j = 1; j <= m; j++) {
            int l = lower_bound(k.begin(),k.end(),seg[j].fir)-k.begin();
            int r = lower_bound(k.begin(),k.end(),seg[j].sec)-k.begin();
            if(l<=i&&r>i) {                             //所有包括这个块的区间全选,不包括的全不选
                p.push_back(j);
                for(int t = l; t < r; t++) {
                    s[t].minn-=1;
                    s[t].maxx-=1;
                }
            }
        }
        int maxx = -1e9;
        for(int j = 0; j < k.size()-1; j++) maxx = max(maxx,s[j].maxx);     //找最大值
        if(maxx-s[i].minn>=ans) {
            ans = maxx-s[i].minn;
            need.clear();
            for(auto x:p) need.push_back(x);
        }
    }
    printf("%d\n%d\n",ans,need.size());
    for(auto x:need) printf("%d ",x);
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值