CF1486D Max Median
找一个区间,长度>=k,让该区间的中位数尽量大。
输出最大中位数。
因为中位数是数组中的一个数,因此我们不枚举区间,我们枚举这个中位数,然后看是否存在长度>=k的区间,使得它在其中成为中位数。
我们对数字x,找以它为中位数的长度最长的区间,如果这个长度>=k,那么ans=max(ans,x)
以它为中位数的,长度为len的区间,如果len是奇数,那么意味着有u=(len-1)/2个数字<=x,同时也有另外u个数字>=x。
当时我做的时候似乎当成了长度等于k的区间了,其实是>=k。
我们真的要观察按照位置排序的数组吗?如果我们存为node,按照数值排序,观察这个数组:
那么,枚举这个数组的数字当作中位数,所谓的长度>=k的区间,在这里也对应新数组的一个长度>=k的区间,但是还得满足区间中的node的位置重排后是连续的,没有空隙。
这又等价于区间node的位置的max-min+1恰好等于区间长度。
突然想到了,我们也许不一定用枚举法,可以用调整法,来否定那些不可能是最大值的中位数。
但还是得固定区间,又沦为枚举了。
在新数组中,对于一个区间,把它右移,得到的中位数一定非严格递增,因此让区间越靠右边越好(对于长度相同的区间而言)
我们枚举新数组的区间的左端点L(注意,它不一定是原数组中的区间的L,甚至新数组的区间对应不了原数组的区间,如果能对应,则称新数组的这个区间为可行区间),那么以其为左端点的可行区间的右端点越远,中位数越大,所以,我们可以从右往左,找第一个可行的右端点R。
[L,R]中的node的位置的max-min=R-L是可行的充要条件。
如今L已经固定,随着区间扩大,max不会变小,min不会变大,因此max-min是递增的,但是R也是递增,两者速率不同阶段可能有所差别,导致相对差距不单调,
我们看L变动的时候,相应的R的变动。(也就是说,看他俩的对应关系)
当L右移一格的时候,max-min,要么不动,要么至少减1,如果不动,那么原来的R-新的L就会<max-min,因此R必须变大,但是如果R能变大,在上一次L的时候就可以变大了,因此R无法变大,
此时L没有对应的R,如果max-min至少减1,那么因为R-L只减了1,因此R-L>=max-min,R应该减小,所以R应当左移。
因此我们发现,只会出现,L右移,R左移,双指针的模式浮现出来。
如今的问题,怎么处理max和min,线段树当然可行,但它有点重量级。。赛场上写这个估计要少不少分数,
因为我们移动都是step by step的,我们用堆/set来存max和min,移动的时候修改堆/set即可。
set 查询max和min的方法:
https://blog.csdn.net/weixin_43304992/article/details/110351528
set 删除用erase(x)就行了。
顺便说下multiset的删除不能用erase(x),除非你要删除所有x,如果只删除一个,先用auto it=s.find(x); 然后再s.erase(it)。
算法还是WA,错误代码:
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,n) for (int i=1;i<=n;i++)
#define REP(i,a,b) for (int i=a;i<=b;i++)
 
#define pb push_back
#define fi first
#define se second
#define pi pair<int,int>
#define mp make_pair
 
typedef long long ll;
typedef complex<double> comp;
 
const int inf=0x3f3f3f3f;
const ll linf=1e18;
const int N=2e5+10;
const double eps=1e-10;
const ll mo=998244353;
int n,k;
int l,r;
struct node {
    int v,p;
} a[N];
set<int> s;
int ans;
bool cmp(node x,node y) {
    if (x.v==y.v) return x.p<y.p;
    return x.v<y.v;
}
int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
 
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n>>k;
    FOR(i,n) cin>>a[i].v;
    FOR(i,n) a[i].p=i;
    sort(a+1,a+1+n,cmp);
    FOR(i,n) s.insert(i);
    l=1,r=n;
    while (l<=r) {
        int len=r-l+1;
        int len2=(*s.rbegin())-(*s.begin())+1;
        if (len2==len) {
            if (len>=k) ans=max(ans,a[(l+r)/2].v);
        } else if (len>len2) {
            s.erase(a[r].p);
            r--;
        }
        s.erase(a[l].p);
        l++;
        if (r<n) {
            s.insert(a[++r].p);
        }
    }
    return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号