题解:P14665 [KenOI 2025] 序列题
Recall_cpp · · 题解
建议评级:黄 + / 绿。
思路
首先这个减操作可以看成对其他的数都
也就是如果把原序列看成一个环,所有的操作都可以看成区间
然后,如果对序列最大值做
所以这样序列最大值就固定了。
因为极差等于最大值减最小值,最大值一定了,当最小值最大的时候,答案最优。
最小值最大,考虑二分最小值。
设二分出来的最小值为
现在我们要求当前情况下最少进行的操作数。
因为是一个环,先破环为链,然后枚举左端点。
设
如果
否则,直接让
但是,在这种情况下,可能会出现
时间复杂度为
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define p_q priority_queue
#define pb push_back
#define mk make_pair
#define pii pair<int,int>
#define ve vector
#define endl '\n'
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define lowbit(x) (x&(-x))
namespace cute_fzj_kuai_ruarua{
int n,m,mx=0,mn=50000;
int a[10005],l[10005],r[10005];
bool check(int x){
for(int i=1;i<=n+n;i++){
l[i]=max(0,x-a[i]);
r[i]=mx-a[i];
}
for(int i=1;i<=n;i++){
int cnt=l[i];
int now=l[i];
for(int j=i+1;j<=i+n-1;j++){
if(l[j]>now){
cnt+=l[j]-now;
now=l[j];
}
if(now>r[j]) now=r[j];
}
if(cnt<=m) return 1;
}
return 0;
}
void main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) mx=max(mx,a[i]);
for(int i=1;i<=n;i++) mn=min(mn,a[i]);
for(int i=1;i<=n;i++){
a[i+n]=a[i];
}
int l=mn,r=mx,ans=mn;
// check(5);
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){
ans=mid;
l=mid+1;
}else r=mid-1;
}
cout<<mx-ans;
}
}
using namespace cute_fzj_kuai_ruarua;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cute_fzj_kuai_ruarua::main();
return 0;
}