1.题目大意
将区间中的某个数+1
将区间中的某个数-1
使一个区间内的数变成全部相等需要的最少操作次数为这个区间的费用
给定n,k和序列a,求a中有多少个费用大于等于k的子区间
2.思路
1.通过观察l,r的性质可知,若[l,r]区间>=k,则[l,r+1]以后的区间都大于等于k,对答案的贡献为
2.采用尺取法枚举两个指针l,r,每次暴力求出中位数,即是,此时,n个点变成a[Mid]的答案最优
3.采用set维护当前值,同时用数组记录数的个数,则最少的所需操作数为,其中,wz为中位数的那个元素,i为set中的元素值
4.若当前操作数<k,则还需扩大区间,使得操作数>=k,同时将新的区间产生的数a[r]加入set中
5.若当前操作数>k,则将区间缩小,更新set中的值
#include <bits/stdc++.h>
//#define int long long
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
int n,m,a[N],r,l,t[N];
LL ans;
set<int> s;
signed main()
{
set<int>::iterator it;
cin>>n>>m;
r=l=1;
for(int i=1;i<=n;i++)
cin>>a[i];
bool f_l=true;
while(r<=n&&l<=r){
int mid=ceil(1.0*(r-l+1)/2),w=0,wz=0;
LL sum=0;
if(f_l){
t[a[r]]++;
s.insert(a[r]);
}
for(it=s.begin();it!=s.end();it++){
w+=t[*it];
if(w>=mid){
wz=*it;
break;
}
}
for(it=s.begin();it!=s.end();it++){
if(wz)
sum+=t[*it]*abs(*it-wz);
}
if(sum<m){
f_l=true;
r++;
}
else{
//cout<<l<<" "<<r<<endl;
ans+=n-r+1;
f_l=false;t[a[l]]--;
if(!t[a[l]]) s.erase(a[l]);
l++;
}
}
cout<<(LL)ans;
return 0;
}