zoukankan      html  css  js  c++  java
  • wqs二分

    wqs二分时间

    给定 [公式] 个物品,我们需要在其中恰好选择 [公式] 个,并且需要最大化收益。设对应的收益为 [公式] ,那么需要满足在最大化收益的前提下,每多选择一个物品,额外产生的收益是单调递减的,也就是 [公式] 。同时,如果我们对物品的选择数量没有限制,即 [公式] 不存在,那么我们应当能够快速地计算出最大的收益,以及达到最大的收益需要选择的物品数量

    wqs二分的使用通俗的理解就是(个人的解释):要求选择k个,然后我们给每个元素加上某个正值后,我们就会更趋向于选更多,加上负值后更趋向于选更少,然后在调整斜率中达到我们需要的范围,然后得出答案。

    当然,按照凸壳和二分斜率理论比较好。

    比较详细的介绍:Here

    下面介绍两个典型例题

    1jisoo

    黑白最小生成树,首先显然问题是个下凸壳,然后给所有的白边统一给一个权值来让我们倾向于选更多/更少的白边

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    template<class T>inline void print(T x)
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)print(x/10);
        putchar('0'+x%10);
    }
    const int maxn=200005;
    struct e{
    	int x;
    	int y;
    	int c;
    	int num;
    	int ans;
    }el[maxn],e2[maxn];
    bool cmp1(e x,e y){
    	if(x.x==y.x) return x.y==y.y?x.c<y.c:x.y<y.y;
    	else return x.x<y.x;
    }
    bool cmp2(e x,e y){
    	return x.y==y.y?x.c<y.c:x.y<y.y;
    }
    int cnt;
    int n,k;
    int tr[maxn];
    int lowbit(int x){
    	return x&-x;
    }
    void add(int x,int kk){
    	for(int i=x;i<=k;i+=lowbit(i)){
    		tr[i]+=kk;
    	}
    }
    int qu(int x){
    	int ans=0;
    	while(x){
    		ans+=tr[x];
    		x-=lowbit(x);
    	}
    	return ans;
    }
    int x,y,z;
    long long ans[maxn];
    void cdq(int l,int r){
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	cdq(l,mid);cdq(mid+1,r);
    	sort(e2+l,e2+mid+1,cmp2);
    	sort(e2+mid+1,e2+r+1,cmp2);
    	int ll=l;
    	for(int rr=mid+1;rr<=r;++rr){
    		while(e2[rr].y>=e2[ll].y&&ll<=mid){
    			add(e2[ll].c,e2[ll].num);
    			ll++;
    		}
    		e2[rr].ans+=qu(e2[rr].c);
    	}
    	for(int i=l;i<ll;++i){
    		add(e2[i].c,-e2[i].num);
    	}
    }
    int main(){
    	read(n);read(k);
    	for(int i=1;i<=n;++i){
    		read(el[i].x);read(el[i].y);read(el[i].c);
    	}
    	sort(el+1,el+n+1,cmp1);
    	for(int i=1;i<=n;++i){
    		if(el[i].x!=el[i-1].x||el[i].y!=el[i-1].y||el[i].c!=el[i-1].c){
    			cnt++;
    			e2[cnt].x=el[i].x;
    			e2[cnt].y=el[i].y;
    			e2[cnt].c=el[i].c;
    			e2[cnt].num=1;
    		}else{
    			e2[cnt].num++;
    		}
    	}
    	cdq(1,cnt);
    	for(int i=1;i<=cnt;++i){
    		ans[e2[i].ans+e2[i].num-1]+=e2[i].num;
    	}
    	for(int i=0;i<n;++i){
    		cout<<ans[i]<<endl;
    	}
    	return 0;
    }
    
    

    2Jennie

    可以通过给每个树加上权值来使我们倾向于多选和少选

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define int long long
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    template<class T>inline void print(T x)
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)print(x/10);
        putchar('0'+x%10);
    }
    int n,k;
    int cnt[5000005];
    int f[5000005];
    int bas[5000005];
    int ans;
    bool check(int x){
    	if(bas[1]+x>0){
    	f[1]=bas[1]+x;
    	cnt[1]=1;
    	}else{
    		if(bas[1]+x==0){
    			f[1]=0;
    			cnt[1]=1;
    		}else{
    		f[1]=0;
    		cnt[1]=0;
    		}
    	}
    	for(int i=2;i<=n;++i){
    		if(f[i-1]>f[i-2]+bas[i]+x){
    			f[i]=f[i-1];
    			cnt[i]=cnt[i-1];
    		}else if(f[i-1]<f[i-2]+bas[i]+x){
    			f[i]=f[i-2]+bas[i]+x;
    			cnt[i]=cnt[i-2]+1;
    		}else{
    			f[i]=f[i-1];
    			cnt[i]=min(cnt[i-1],cnt[i-2]+1);
    		}
    	}
    	return cnt[n]<=k;
    }
    signed main(){
    	read(n);read(k);
    	for(int i=1;i<=n;++i){
    		read(bas[i]);
    	}
    	int l=-2000000;
    	int r=0;
    	int mid;
    	ans=-1;
    	while(l<=r){
    		 mid=(l+r)/2;
    		if(check(mid)){
    			l=mid+1;
    			//if(cnt[n]<=k)
    			ans=f[n]-mid*k;
    		}else{
    			r=mid-1;
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    老李分享:qtp自动化测试框架赏析-关键字自动化测试框架
    QTP自动化测试培训:描述编程之WebElement
    测试开发Python培训:自动发布新浪微博-技术篇
    老李分享:开发python的unittest结果输出样式
    布隆过滤器
    缓存击穿、缓存穿透、缓存雪崩
    JVM锁优化
    Java 异常体系
    常用的SQL调优
    Mysql 索引
  • 原文地址:https://www.cnblogs.com/For-Miku/p/15498818.html
Copyright © 2011-2022 走看看