• JXOI2017 加法


    题目描述:
    可怜有一个长度为 \(n\) 的正整数序列 \(A\),但是她觉得 \(A\) 中的数字太小了,这让她很不开心。

    于是她选择了 \(m\) 个区间 \([l_i, r_i]\) 和两个正整数 \(a\), \(k\)。她打算从这 \(m\) 个区间里选出恰好$ k$ 个区间,并对每个区间执行一次区间加\(a\) 的操作。(每个区间最多只能选择一次。)

    对区间 $[l, r] \(进行一次加\) a \(操作可以定义为对于所有 \)i \in [l, r]$ ,将 \(A_i\) 变成 \(A_i + k\)。现在可怜想要知道怎么选择区间才能让操作后的序列的最小值尽可能的大,即最大化\(min{A_i}\)

    数据范围:
    \(n,m \leq 200 ,T \leq 2000,k \leq m,a \leq 100,A_i \leq 10^8\)

    题解:
    差点以为做了个假题...
    疯狂T:二分写炸

    直接二分最小值判断即可,维护最小值用优先队列。


    等等...这题不是T1?

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e5 + 10;
    int n,m,k,v;
    priority_queue<int>q;
    struct node {
        int l;
        int r;
    }dat[MAXN];
    int a[MAXN];
    int c[MAXN];
    int T,l,r;
    int cnt;
    int ans;
    bool cmp(node a,node b) {
        return a.l == b.l ? a.r < b.r : a.l < b.l;
    }
    bool ok(int mid) {
        memset(c,0,MAXN);
        cnt = 0;
        while(!q.empty()) q.pop();
        int it = 1;
        for(int i = 1;i <= n; ++i) {
            while(it <= m and dat[it].l <= i) {
                q.push(dat[it].r);
                it ++;
            }
            c[i] += c[i - 1];
            while(!q.empty() and c[i] + a[i] < mid and cnt < k) {
                int x = q.top();q.pop();
                if(x >= i) {
                    c[i] += v;
                    c[x + 1] -= v;
                    ++cnt;
                }
            }
            if(c[i] + a[i] < mid) return 0;
        }
        return 1;
    }
    int read () {
        int q=0,f=1;char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')f=-1;ch=getchar();
        }
        while(isdigit(ch)){
            q=q*10+ch-'0';ch=getchar();
        }
        return q*f;
    }
    int main (){
        T = read();
        while(T--) {
            n = read(),m = read(),k = read(),v = read();
            l = INT_MAX;
            for(int i = 1;i <= n; ++i) {
                a[i] = read();
                l = min(l,a[i]);
            }
            r = 0x3f3f3f3f;
            for(int i = 1;i <= m; ++i) {
                dat[i].l = read();
                dat[i].r = read();
            }
            sort(dat + 1,dat + m + 1,cmp);
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(ok(mid)) {
                    l = mid + 1;
                    ans = mid;
                }
                else r = mid - 1;
            }
            printf("%d\n",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    iOS 根据生日计算生肖
    iOS 生日计算星座
    iOS App设置icon,启动图
    iOS UITextFiled基本解析
    自定义tabbaritem上的badeg
    iOS摄像头和相册-UIImagePickerController-浅析
    C++ 类型转换操作与操作符重载 operator type() 与 type operator()
    c++中的强制转换
    啊里巴巴上市--马云的励志话
    争--转任志强
  • 原文地址:https://www.cnblogs.com/akoasm/p/10121453.html
Copyright © 2020-2023  润新知