CSU1928-又是第K大-二分&&CF981-D-Bookshelves

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题目:传送门

 (原题目描述及样例在最下面。)
 题意很简单,给两个长度为n(5e4)的序列a,b。问新序列c中第k大的元素。
 新序列c就是a和b中两两相加得出的序列。

思路:

 把a和b序列排序后,二分。
 二分上界为a[n-1]+b[n-1],二分下界为a[0]+b[0]。

 注意爆int了。要用longlong。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int N = 50000+5;
int n;
LL k;
int ar[N],br[N];
LL num(int m){
    LL cnt=0;
    for(int i=0;i<n;++i){
        int p=upper_bound(ar,ar+n,m-br[i])-ar;
        cnt+=p;
    }
    return cnt;
}
int main(){
    while(~scanf("%d%lld",&n,&k)){
        for(int i=0;i<n;++i){
            scanf("%d",&ar[i]);
        }
        for(int i=0;i<n;++i){
            scanf("%d",&br[i]);
        }
        sort(ar,ar+n);sort(br,br+n);
        int l=ar[0]+br[0],r=ar[n-1]+br[n-1],m,ans;
        while(l<=r){
            m=(l+r)>>1;
            if(num(m)>=k){
                r=m-1;
                ans=m;
            }else{
                l=m+1;
                ans=m+1;
            }
        }//5 6 6 7 7 7 8 8 9
        printf("%d\n",ans );
    }
    return 0;
}


题目描述:

Description
给出两个长度均为n的数组A、B。而C数组是A和B合成的,长度为n*n,并且满足等式c[(j-1)*n+k]= a[j]+b[k] (1<=j、k<=n)
其实就是说C中的元素分别是A[1]+B[1]、A[1]+B[2]、……、A[1]+B[n]、A[2]+B[1]、……、A[2]+B[n]、……、A[n]+B[n]
求C中第K大的元素的值(从小到大排序后的第k个)

Input
输入包括不超过15组数据
第一行有两个数,分别为A、B的长度n以及k(1<=n<=50000,1<=k<=min(n*n,1000000000))
第二行n个值为数组A (1<=A[i]<=50000)
第三行n个值为数组B (0<=B[i]<=50000)

Output
输出一行,为C数组中第K大的数

Sample Input
3 4
1 2 3
4 5 6
Sample Output
7
Hint
Source
中南大学2017年5月月赛

Author
卢铭威


CF981D:

 把n个数字分成k段,每一段的值等于那一段所有数字之和,问k段数字逻辑和最大是多少?

思路:

因为逻辑和最大不超过long long,我们就从高到低枚举每一位为1的情况。
判断是否可以可行的过程,用dp[i][j]=1或0表示前i个数字为分成j段,逻辑和能否为x。
if(sum[i]&x==x)dp[i][1]=1;
if((sum[i]-sum[j])&x==x)dp[i][h]|=dp[j][h-1]

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 55;
const int INF = 0x3f3f3f3f;
int n,k;
LL sum[N],d[N][N];
LL check(LL x){
    memset(d,0,sizeof(d));
    for(int i=1;i<=n;++i){
        if((sum[i]&x)==x){
            d[i][1]=1;
        }
        for(int j=1;j<i;++j){
            if(((sum[i]-sum[j])&x)!=x)continue;
            for(int h=2;h<=min(k,i);++h){
                d[i][h]|=d[j][h-1];
            }
        }
    }
    return d[n][k];
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        sum[0]=0;
        for(int i=1;i<=n;++i){
            scanf("%lld",&sum[i]);
            sum[i]+=sum[i-1];
        }
        LL ans=0;
        for(int i=60;i>=0;--i){
            if(check(ans|(1LL<<i))){
                ans|=(1LL<<i);
            }
        }
        printf("%lld\n",ans );
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/80694473