题意:给你n个数,m个范围,可以选择任意个范围中的数所有都减一,问如何得到最大的 max-min。
题目链接
简单版本直接暴力枚举每个数分别为最大最小,时间复杂度 nnm;
#include<bits/stdc++.h>
#define fi first
#define se second
#define FOR(a) for(int i=0;i<a;i++)
#define sc(a) scanf("%d",&a)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 1e17 + 10;
const int N = 1e5+10;
const ll mod = 1000000007;
const int base=131;
map<string, int>ml;
int a[N],n,m,t,k,flag,l[N],r[N],cnt;
int vis[N];
vector<int> v,ev;
priority_queue<int> q;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++)
{
cin>>l[i]>>r[i];
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cnt=a[i]-a[j];
for(int k=1;k<=m;k++)
{
if(j<=r[k]&&j>=l[k])
{
if(i<l[k]||i>r[k])
{
cnt++;
v.push_back(k);
}
}
}
if(ans<cnt)
{
ev.clear();
ans=cnt;
for(auto x:v) ev.push_back(x);
}
v.clear();
}
}
cout<<ans<<endl;
cout<<ev.size()<<endl;
for(auto x:ev) cout<<x<<" ";
}
复杂版本:由于n太大,无法进行暴力枚举,看题解才知道解法。
此时枚举每个为最小值,我们要使最后答案最大,所以我们要竟可能减小我们选定的最小值,那么我们可以利用差分数组的思想,保存每一个区间的起始位置和结束位置,然后从1开始枚举最小值位置。那么现在假设1是最小值的位置,我们就应该把包含1的区间全部选中,那么显然,只有以1开始的区间是包含1的,那么我们直接修改数组,把这些区间全部-1。然后再去寻找数组中的最大值,就可以算出1是最小值时的x。
然后枚举到2,因为1开始的区间已经在数组里改过了,那么我们只需要把2开始的区间再全部选中并且-1,那么所有包含2的区间不就都被选中了吗?这时候再寻找数组中的最大值,就可以算出2是最小值时的x。如果有一个区间是从1到1怎么办?枚举到2的时候这个区间是不应该被选的(因为不包含2),所以在判断完位置1之后,应该把所有以1结束的区间重新“退选”,即把这些区间再+1,恢复到没选的状态。这样就保证在枚举i位置为最小值时,当前选中的区间都包含i,没有其他无关区间。
区间修改+区间查询最大值,用线段树维护即可。对于每个区间,只有选择和退选的操作,也就是只修改了2*m次的区间。对于每个位置的i都需要查询最大值。复杂度为(n+2m)*logn,由于m很小,复杂度约为nlogn。
这里借鉴了大佬博客:
https://blog.csdn.net/qq_41643650/article/details/86620128
#include<bits/stdc++.h>
#define fi first
#define se second
#define FOR(a) for(int i=0;i<a;i++)
#define sc(a) scanf("%d",&a)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 1e17 + 10;
const int N = 1e5+10;
const ll mod = 1000000007;
const int base=131;
map<string, int>ml;
ll a[N],n,m,t,k,flag,l[N],r[N],cnt;
ll lazy[N<<2];
ll tree[N<<2];
vector<int> st[N],en[N],v;
priority_queue<int> q;
void push_up(int rt)
{
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void push_down(int rt)
{
if(lazy[rt])
{
lazy[rt<<1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
tree[rt<<1]+=lazy[rt];
tree[rt<<1|1]+=lazy[rt];
lazy[rt]=0;
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
cin>>tree[rt];
return ;
}
int m=l+r >>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
push_up(rt);
}
void update(int L,int R,int x,int rt,int l,int r)
{
if(L<=l&&r<=R)
{
tree[rt]+=x;
lazy[rt]+=x;
return;
}
push_down(rt);
int m=l+r >>1;
if(L<=m) update(L,R,x,rt<<1,l,m);
if(R>m) update(L,R,x,rt<<1|1,m+1,r);
push_up(rt);
}
ll query(int L,int R,int rt,int l,int r)
{
if(L<=l&&r<=R) return tree[rt];
int m=l+r>>1;
push_down(rt);
ll ans=-1e9;
if(L<=m) ans=max(ans,query(L,R,rt<<1,l,m));
if(R>m) ans=max(ans,query(L,R,rt<<1|1,m+1,r));
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int x,y;
cin>>n>>m;
build(1,1,n);
for(int i=1;i<=m;i++)
{
cin>>x>>y;
l[i]=x;
r[i]=y;
st[x].push_back(y);
en[y].push_back(x);
}
ll res=-inf;
for(int i=1;i<=n;i++)
{
for(int j=0;j<st[i].size();j++)
update(i,st[i][j],-1,1,1,n);
cnt=query(1,n,1,1,n)-query(i,i,1,1,n);
if(cnt>res)
{
res=cnt;
k=i;
}
for(int j=0;j<en[i].size();j++)
update(en[i][j],i,1,1,1,n);
}
//show2("k",k)
cout<<res<<endl;
for(int i=1;i<=m;i++)
{
if(k>=l[i]&&k<=r[i])
v.push_back(i);
}
cout<<v.size()<<endl;
for(auto x:v) cout<<x<<" ";
}