传送门

外边二分,里面拿线段树维护贪心就行了。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define MN 110000
#define lp p<<1
#define rp p<<1|1 
using namespace std;

vector<int> v[MN];
int t,n,s,a[MN],o[MN],z[MN<<2];
bool cmp(int x,int y){return a[x]==a[y]?x<y:a[x]<a[y];}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
void add(int p,int l,int r,int k,int v){
    z[p]=max(z[p],v);
    if (l==r) return;
    int mid=l+r>>1;
    if (k<=mid) add(lp,l,mid,k,v);else add(rp,mid+1,r,k,v);
}
int ask(int p,int l,int r,int L,int R){
    if (l==L&&r==R) return z[p];
    int mid=l+r>>1;
    if (R<=mid) return ask(lp,l,mid,L,R);else
    if (L>mid) return ask(rp,mid+1,r,L,R);else
    return max(ask(lp,l,mid,L,mid),ask(rp,mid+1,r,mid+1,R));
}
inline bool ju(int k){
    long long o=0;
    int la=0,e=0;
    memset(z,0,(n+5)*16);
    for (int i=0;v[i].size();i++){
        for (int j=0;j<v[i].size();){
            int w,m;
            for (w=j+1;w<v[i].size();w++)
            if (v[i][w]-v[i][w-1]>k) break;
            m=ask(1,1,n,max(1,v[i][j]-k),min(n,v[i][w-1]+k))+1;
            for (;j!=w;j++)    o+=m,add(1,1,n,v[i][j],m);
        }
    }
    return o<=s;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&s);
        for (int i=0;i<n;i++) scanf("%d",&a[i]),o[i]=i;
        sort(o,o+n,cmp);v[0].push_back(o[0]+1);
        for (int i=1,j=0;i<n;i++) j+=a[o[i]]!=a[o[i-1]],v[j].push_back(o[i]+1);
        int l=0,r=n;
        while (l<r){
            int mid=l+r+1>>1;
            if (ju(mid)) l=mid;else r=mid-1;
        }
        printf("%d\n",ju(l)?l+1:0);
        for (int i=0;i<n;i++) v[i].clear();
    }
}
View Code

相关文章:

  • 2022-12-23
  • 2021-10-12
  • 2021-07-07
  • 2022-12-23
  • 2021-12-24
  • 2021-12-27
  • 2022-02-19
  • 2021-11-24
猜你喜欢
  • 2021-09-19
  • 2021-08-19
  • 2022-01-20
  • 2021-07-10
  • 2022-01-09
  • 2021-12-24
  • 2021-05-25
相关资源
相似解决方案