zoukankan      html  css  js  c++  java
  • Codeforces Round #703 (div2)

    A. Shifting Stacks (*900)

    题意

    (n(1leq nleq 100))堆块,每堆有一个高度(h_i(0leq h_ileq 1e9)),可以从第(i)堆移动一个块到第((i+1))堆,能否实现整个序列严格单调递增?

    题解

    严格单调递增时,前(i)堆总和最小时,高度依次为(0,1,2,3,cdots),总和最小值(frac{i(i-1)}{2})。所以只需要检查每个位置的前缀和是否大于等于(frac{i(i-1)}{2})

    #include<bits/stdc++.h>
    #define LL long long
    #define lowbit(x) x&(-x)
    #define eps 1e-6
    using namespace std;
    
    const int maxn=110;
    
    int T,n;
    LL a[maxn];
    
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
            LL need=0,sum=0;
            bool f=true;
            for(int i=1;i<=n;i++){
                need+=i-1;
                sum+=a[i];
                if(sum<need){
                    f=false;
                    break;
                }
            }
            printf("%s
    ",f?"YES":"NO");
        }
    }
    

    B. Eastern Exhibition (*1500)

    题意

    二维平面上有(n(1leq nleq 1000))座房屋,每座房屋有横纵坐标(x_i,y_i(0leq x_i,y_ileq 1e9)),计算平面上到所有房屋的曼哈顿距离最小的点的个数

    题解

    首先,问题不是二维的,因为两个一维互不影响,所以可以转化为对一维求解,再将答案相乘
    对于一维情况,也就是一条直线上的点,有已知结论:总数为奇数时,中间的点符合条件,总数为偶数时,中间的两个点以及它们中间的点符合条件

    #include<bits/stdc++.h>
    #define LL long long
    #define lowbit(x) x&(-x)
    #define eps 1e-6
    using namespace std;
    
    const int maxn=1010;
    int T,n;
    LL x[maxn],y[maxn];
    
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++) scanf("%lld %lld",&x[i],&y[i]);
            sort(x+1,x+1+n);
            sort(y+1,y+1+n);
            LL ans1=1,ans2=1;
            if(n%2==0){
                ans1=(x[n/2+1]-x[n/2])+1;
                ans2=(y[n/2+1]-y[n/2])+1;
            }
            printf("%lld
    ",ans1*ans2);
        }
    }
    

    C1. Guessing the Greatest (easy version) (*1600)

    题意

    交互题
    有一个长度为(n(1leq n leq 1e5))的数组,每次可以选择一个区间([l,r](1leq l,r leq n)),询问区间内次大值的位置。在不超过(40)次询问中找到数组中最大值的下标

    题解

    二分
    由于(2^{17}approx 1e5),所以使用二分时,需要在(2)次询问中确定最大值位于左半边还是右半边。首先询问([l,r])内的次大值的位置,设为(smax),之后二分区间([l,r]),设(mid=frac{(l+r)}{2}),在两个区间([l,mid])([mid+1,r])中,如果(smax)所在区间长度大于(1),再询问(smax)所在区间的次大值的位置,如果依然是(smax),则说明最大值在这个区间中,否则说明最大值在另一个区间中

    #include<bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define LD long double
    #define PII pair<int,int>
    #define PLL pair<LL,LL>
    #define PLI pair<LL,int>
    #define pi acos(-1.0)
    #define eps 1e-6
    #define lowbit(x) x&(-x)
    using namespace std;
    
    int n;
    
    int main(){
        scanf("%d",&n);
        int l=1,r=n;
        while(r>l){
            printf("? %d %d
    ",l,r);
            fflush(stdout);
            int smax;
            scanf("%d",&smax);
            int mid=(l+r)>>1;
            if(smax<=mid){
                if(l==mid){
                    l=mid+1;
                    continue;
                }
                printf("? %d %d
    ",l,mid);
                fflush(stdout);
                int t;
                scanf("%d",&t);
                if(t==smax){
                    r=mid;
                }
                else l=mid+1;
            }
            else{
                if(mid+1==r){
                    r=mid;
                    continue;
                }
                printf("? %d %d
    ",mid+1,r);
                fflush(stdout);
                int t;
                scanf("%d",&t);
                if(t==smax){
                    l=mid+1;
                }
                else r=mid;
            }
        }
        printf("! %d
    ",r);
    }
    

    C2. Guessing the Greatest (hard version) (*1900)

    题意

    (c1)提高版,在不超过(20)次询问中找到数组中最大值的下标

    题解

    首先通过两次询问找到最大值位于次大值左边还是右边,具体方法是首先找到次大值的位置(smax),之后询问([1,smax]),如果结果仍为(smax),说明最大值位于([1,smax]),否则说明最大值位于([smax+1,r])。之后每次经过一次询问二分区间,询问的是以(smax)为一个端点,二分另一个端点得到的区间,总询问次数为(2+lceil log_21e5 ceil=19)

    #include<bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define LD long double
    #define PII pair<int,int>
    #define PLL pair<LL,LL>
    #define PLI pair<LL,int>
    #define pi acos(-1.0)
    #define eps 1e-6
    #define lowbit(x) x&(-x)
    using namespace std;
    
    int n;
    
    int main(){
        scanf("%d",&n);
        printf("? %d %d
    ",1,n);
        fflush(stdout);
        int smax,t;
        scanf("%d",&smax);
        if(smax>1){
            printf("? %d %d
    ",1,smax);
            fflush(stdout);
            scanf("%d",&t);
        }
        int l,r;
        if(smax>1 && t==smax){
            l=1;
            r=smax-1;
            while(r>l){
                int mid=(l+r+1)>>1;
                printf("? %d %d
    ",mid,smax);
                fflush(stdout);
                int tt;
                scanf("%d",&tt);
                if(tt==smax) l=mid;
                else r=mid-1;
            }
        }
        else{
            l=smax+1;
            r=n;
            while(r>l){
                int mid=(l+r)>>1;
                printf("? %d %d
    ",smax,mid);
                fflush(stdout);
                int tt;
                scanf("%d",&tt);
                if(tt==smax) r=mid;
                else l=mid+1;
            }
        }
        printf("! %d
    ",r);
    }
    

    D. Max Median (*2100)

    题意

    有一个长度为(n(1leq nleq 2e5))的数组(a)(1leq a_ileq n),中位数定义为将一个序列按照递增排序之后下标为(lfloor frac{(n+1)}{2} floor)的数。给定(k(1leq kleq n)),计算数组(a)中长度至少为(k)并且中位数最大的连续子段的中位数的值

    题解

    二分答案,设二分出的值是(x),判断数组中是否存在满足条件,并且中位数大于等于(x)的子段
    将数组(a)处理成只包含(-1,1)的数组,方法为如果(a_igeq x),则赋为(1),否则赋为(-1)。这样如果某个子段的中位数至少是(x),等价于子段和为正数
    问题转化为寻找长度至少为(k),并且子段和最大的子段,判断子段和是否为正数
    计算前缀和,扫一遍数组,计算以位置(i)结尾的满足条件的子段的最大子段和,具体方法是用(i)的前缀和减去(0,1,cdots,i-k)中最小的前缀和
    时间复杂度(O(nlog n))

    #include<bits/stdc++.h>
    #define LL long long
    #define lowbit(x) x&(-x)
    #define eps 1e-6
    using namespace std;
    
    const int maxn=200010;
    
    int n,k,a[maxn],b[maxn];
    
    bool check(int x){
        for(int i=1;i<=n;i++){
            if(a[i]>=x) b[i]=1;
            else b[i]=-1;
        }
        for(int i=1;i<=n;i++) b[i]+=b[i-1];
        int ans=b[k];
        int mini=0;
        for(int i=k+1;i<=n;i++){
            mini=min(mini,b[i-k]);
            ans=max(ans,b[i]-mini);
        }
        return ans>0;
    }
    
    int main(){
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int l=1,r=n;
        while(r>l){
            int mid=(l+r+1)>>1;
            if(check(mid)) l=mid;
            else r=mid-1;
        }
        printf("%d
    ",r);
    }
    

    E

    F

  • 相关阅读:
    正在找工作/打算找工作的看过来!
    xx星空面试题
    买的书不少,看的书不多,这是病
    公司那么多 我想去面面
    Android设备直接运行java项目?还杀不死?
    node-sass安装失败 解决办法(linux和window)
    Vue + element控制鼠标右键菜单
    Vue.js中Promise、异步、同步、定时器
    选择器&伪类选择器
    根据城市名称获取对应的省份名称
  • 原文地址:https://www.cnblogs.com/fxq1304/p/14423936.html
Copyright © 2011-2022 走看看