Codeforces Round #535 E2-Array and Segments (Hard version)
题意:
给你一个数列和一些区间,让你选择一些区间(选择的区间中的数都减一),
求最后最大值与最小值的差值最大,并输出选择的区间
思路:
在n=300的时候,我们是枚举每个数作为最小值,应用所有覆盖它的区间,并且没
次都更行差值的最大值。
但是这里的n=1e5,所以我们不能用O(n*n*m),但是我们看到这里的m=300
所以可以从m入手,枚举区间,就是记录每个区间的两个端点,利用差分的思想,
来枚举更新最大值
这里说一下为什么枚举最小值,因为如果最大值也在这个区间则抵消,如果没在则
更好
#include<bits/stdc++.h> using namespace std; #define MAX 100005 int n,m; vector<int>add[MAX],sub[MAX],a(MAX); vector<pair<int,int > >b(MAX); void change(int l,int r,int x) { for(int i=l;i<=r;i++) { a[i]+=x; } } int main() { while(~scanf("%d %d",&n,&m)) { for(int i=0;i<m;i++) sub[i].clear(); for(int i=0;i<m;i++) add[i].clear(); for(int i=0;i<n;i++) { scanf("%d",&a[i]); } for(int i=0;i<m;i++) { scanf("%d %d",&b[i].first,&b[i].second); b[i].first--; b[i].second--; sub[b[i].first].push_back(i); add[b[i].second+1].push_back(i); } int minn,maxn; minn=maxn=a[0];//注意这里不要习惯把minn=INF,maxn=0,因为a数组元素可能为负数,比如-1,这样ans=1,容易出错 for(int i=1;i<n;i++) { maxn=max(maxn,a[i]); minn=min(minn,a[i]); } int ans=maxn-minn; int c=-1; for(int i=0;i<n;i++) { //应用覆盖的区间 for(int j=0;j<sub[i].size();j++) { int ind=sub[i][j]; change(b[ind].first,b[ind].second,-1); } //消除之前的区间 for(int j=0;j<add[i].size();j++) { int ind=add[i][j]; change(b[ind].first,b[ind].second,1); } int minn=maxn=a[0]; if(add[i].size()||sub[i].size()) { for(int j=1;j<n;j++) { maxn=max(maxn,a[j]); minn=min(minn,a[j]); } if(maxn-minn>ans) { ans=maxn-minn; c=i; } } } int len=0; int mask[MAX]; for(int i=0;i<m;i++) { if(b[i].first<=c&&c<=b[i].second) { mask[len++]=i; } } printf("%d ",ans); printf("%d ",len); for(int i=0;i<len;i++) { printf("%d ",mask[i]+1); } } return 0; }