kuangbin专题23 二分 尺取 单调栈队列

对于位置问题似乎是可以考虑二分选择出合法的位置Queue Pie Median这三题都是这样子的

                      Pie

//想分解公式但是什么都没看出来,这个公式是用于判断单调性的
//主函数里面二分答案,check二分查找有多少个小于当前M的数
//对于相同的j,i越大结果越大
题意:给你一个n * n的矩阵,矩阵一点的值是i^2 + 100000 × i + j^2 - 100000 × j + i × j,问在整个矩阵中第m大的值是多少。
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<string.h>
#include<stdio.h>
#include<queue>
#include<stack> 
#include<set>
#define endl "\n"
typedef long long ll;
using namespace std;
const int N=1e5+5;
int n,a[N],m;
bool check(int x){
    int cnt=0;
    //cout<<x<<endl;
    for(int i=1;i<=n;i++){
        cnt+=n-(lower_bound(a+1,a+1+n,a[i]+x)-a-1);
        //cout<<a[i]+x<<endl;
    }
    //cout<<x<<' '<<cnt<<endl;
    return cnt>m;
}
int main(){
    while(~scanf("%d",&n)){
        m=n*(n-1)/4;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        int L=0,R=a[n]-a[1];
        while(L+1<R){
            int M=(L+R)>>1;
            if(check(M))L=M;
            else R=M;
        }
        printf("%d\n",L);
    }
    return 0;
}

 

   

                   Median

 和Matrix很像,排序后对于一个固定的 i ,越在后面的 j 差值一定是越大的,抓住这个性质,枚举 i  二分 j 即可

#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<string.h>
#include<stdio.h>
#include<queue>
#include<stack> 
#include<set>
#define endl "\n"
typedef long long ll;
using namespace std;
const int N=1e5+5;
int n,a[N],m;
bool check(int x){
    int cnt=0;
    //cout<<x<<endl;
    for(int i=1;i<=n;i++){
        cnt+=n-(lower_bound(a+1,a+1+n,a[i]+x)-a-1);
        //cout<<a[i]+x<<endl;
    }
    //cout<<x<<' '<<cnt<<endl;
    return cnt>m;
}
int main(){
    while(~scanf("%d",&n)){
        m=n*(n-1)/4;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        int L=0,R=a[n]-a[1];
        while(L+1<R){
            int M=(L+R)>>1;
            if(check(M))L=M;
            else R=M;
        }
        printf("%d\n",L);
    }
    return 0;
}

 

 

//------------------------------------------------

浮点数二分                                          

                                                Pie

 

#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<string.h>
#include<stdio.h>
#include<queue>
#include<stack> 
#include<set>
#include<iomanip>
#define endl "\n"
#define PI acos((double)-1)
typedef long long ll;
using namespace std;
const int N=1e4+5;
const double eps=1e-8;
int n,m,a[N];
bool check(double x){
    int cnt=0;
    for(int i=1;i<=n;i++){
        cnt+=(int)(a[i]/x);
    }
    return cnt>=m;
}
int main(){
    //ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int T=1;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        double sum=0;m++;
        //不能在这就计算整个派的体积(二分体积除以Π,最后输出答案再乘上Π,会更精确,防止因为精度问题wa)
        for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i]*=a[i];sum+=a[i];}
        double L=0,R=sum/m;
        while(R-L>eps){
            double M=(L+R)/2;
            if(check(M))L=M;
            else R=M;
        }
        printf("%.6f\n",L*PI);
    }
    return 0;
}

二分+树状数组 

 

Queue - HDU 5493 

 

#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<string.h>
#include<stdio.h>
#include<queue>
#include<stack> 
#include<set>
#include<iomanip>
#define endl "\n"
#define int long long
#define PI acos((double)-1)
typedef long long ll;
using namespace std;
const int N=2e5+5;
struct Node{
    int h,num;
}a[N];
bool cmp(Node x,Node y){
    return x.h<y.h;
}
int Tree[N],ans[N],n;
void modify(int x,int k) {
    for (; x < N; x += x & (-x)) {
        Tree[x] += k;
    }
}
int qurey(int x) {
    int ans = 0;
    for (; x; x -= x & (-x)) {
        ans += Tree[x];
    }
    return ans;
}
int find(int x){
    //树状数组L不能是0,写法也要变成L<R而不是L+1<R
    int L=1,R=n;
    while(L<R){
        int M=(L+R)>>1;
        if(qurey(M)<x)L=M+1;
        else R=M;
    }
    return L;
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int T=1;cin>>T;
    int now=0;
    while(T--){
        now++;
        memset(Tree,0,sizeof(Tree));
        cin>>n;
        for(int i=1;i<=n;i++){
            //每个可能有人的位置加一
            modify(i,1);
            cin>>a[i].h>>a[i].num;
        }
        int flag=0;
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++){
            if(n-i-a[i].num<0){
                flag=1;
                break;
            }
            int x=min(n-i-a[i].num,a[i].num)+1;
            int pos=find(x);
            //因为高度是sort后的,后面的高度只会越来越大,当前位置是不可能比后面的位置高的
            //故将这个点变回0
            modify(pos,-1);
            ans[pos]=a[i].h;
            //cout<<pos<<' '<<a[i].h<<endl;
        }
        cout<<"Case #"<<now<<": ";
        if(flag)cout<<"impossible\n";
        else {
            for(int i=1;i<=n;i++)cout<<ans[i]<<" \n"[i==n];
            //cout<<endl;
        }
    }
    return 0;
}

 

posted @ 2023-06-07 16:43  zhujio  阅读(22)  评论(0)    收藏  举报