• [P4064][JXOI2017]加法(贪心+树状数组+堆)


    题目描述

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

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

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

    输入输出格式

    输入格式:

    第一行输入一个整数表示数据组数。

    对于每组数据第一行输入四个整数 n, m, k, a。

    第二行输入 n 个整数描述序列 A。

    接下来 m 行每行两个整数 li, ri 描述每一个区间。数据保证所有区间两两不同。

    输出格式:

    对于每组数据输出一个整数表示操作后序列最小值的最大值。

    输入输出样例

    输入样例#1: 复制
    1 
    3 3 2 1
    1 3 2
    1 1
    1 3
    3 3
    输出样例#1: 复制
    3

    说明

    选择给区间 [1, 1] 和 [1, 3] 加 1。

    对于100%的数据,保证1≤n,m≤200,1leq n,m leq 200, 1n,m200, 1≤T≤2000,1≤k≤m,1≤a≤100,1≤Ai≤1081leq Tleq 2000, 1 ≤ k ≤ m, 1 ≤ a ≤ 100, 1 ≤ A_i ≤ 10^81T2000,1km,1a100,1Ai108

    不要相信数据范围,应该是$1leq n,m leq 10^5$。

    二分答案,贪心扫一遍,对于小于二分值的位置,用堆找到包含它且向右延伸最长的区间加上它,区间加用差分树状数组实现。

     1 #include<cstdio>
     2 #include<queue>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define rep(i,l,r) for (int i=l; i<=r; i++)
     6 using namespace std;
     7 
     8 const int N=200100;
     9 priority_queue<int>Q;
    10 int T,n,m,k,A,q[N],a[N],c[N],stk[N];
    11 struct P{ int l,r; }p[N];
    12 bool cmp(P a,P b){ return a.l<b.l; }
    13 void add(int x,int k){ for (; x<=n+1; x+=x&-x) c[x]+=k; }
    14 int que(int x){ int res=0; for (; x; x-=x&-x) res+=c[x]; return res; }
    15 
    16 bool chk(int lim){
    17     while (!Q.empty()) Q.pop();
    18     memset(c,0,sizeof(c)); int top=0,j=1,cnt=0;
    19     rep(i,1,n) if (a[i]<lim) stk[++top]=i;
    20     rep(i,1,top){
    21         while (j<=m && p[j].l<=stk[i]) Q.push(p[j].r),j++;
    22         while (a[stk[i]]+que(stk[i])<lim){
    23             cnt++; if (cnt>k || Q.empty()) return 0;
    24             int x=Q.top(); Q.pop(); add(stk[i],A); add(x+1,-A);
    25         }
    26     }
    27     return 1;
    28 }
    29 
    30 int main(){
    31     freopen("P4064.in","r",stdin);
    32     freopen("P4064.out","w",stdout);
    33     for (scanf("%d",&T); T--; ){
    34         scanf("%d%d%d%d",&n,&m,&k,&A);
    35         rep(i,1,n) scanf("%d",&a[i]);
    36         rep(i,1,m) scanf("%d%d",&p[i].l,&p[i].r);
    37         sort(p+1,p+m+1,cmp);
    38         int l=1,r=120000000,mid,ans;
    39         while (l<=r){
    40             mid=(l+r)>>1;
    41             if (chk(mid)) ans=mid,l=mid+1; else r=mid-1;
    42         }
    43         printf("%d
    ",ans);
    44     }
    45     return 0;
    46 }
  • 相关阅读:
    博客园特效页脚保存
    go channel
    goland 注册
    mac安装go环境
    go 结构体与方法
    gin教程
    hihocoder234周 计算不包含黑点的矩形个数
    参考文献的正确姿势
    vscode用法
    使用extract-text-webpack-plugin提取css文件
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8806344.html
Copyright © 2020-2023  润新知