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;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇