Codechef August Challenge 2018 : Coordinate Compression

传送门算法解析
本文介绍了一种名为“传送门”的算法题目解决方案,采用外层二分查找与内层线段树维护的方式进行贪心求解。该算法适用于解决特定类型的问题,通过线段树维护中间结果,利用二分查找缩小搜索范围。

传送门

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

#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

 

转载于:https://www.cnblogs.com/Enceladus/p/9493909.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值