HDU 3486 RMQ+二分

点击打开链接

题意:n个人,分成m组,多的人就不要了,每组的人都是顺序的,每组选出一个分最高的人,问你最少需要多少人他们的和>k

思路:因为要人数最少,直接想到了二分去求解,然后查询区间的最大值可以用RMQ直接快速查询,但是过了之后看讨论发现二分的是错的,好心人的数据是这样的

10 1500

1 1 1 1 1000 1000 1 1 1 1

明显分成两组两个人就可以了,但是我的AC代码输出的是6,看了看发现里面的数其实是不符合单调的性质的,所以不正确,然后翻了翻有人说枚举组数就可以过,这数据不敢恭维,不正确的算法以及相当暴力的写法竟然都可以过,有人有正确解法求告知,这里贴个二分的

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=200010;
int dp[maxn][20],num[maxn];
void RMQ_init(int n){
    for(int i=1;i<=n;i++)
        dp[i][0]=num[i];
    for(int i=1;(1<<i)<=n;i++){
        for(int j=1;j+(1<<i)-1<=n;j++){
            dp[j][i]=max(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
        }
    }
}
int RMQ(int le,int ri){
    int k=0;
    while((1<<(k+1))<=ri-le+1) k++;
    int ans1=max(dp[le][k],dp[ri-(1<<k)+1][k]);
    return ans1;
}
bool judge(int n,int m,int k){
    int t=m,sum=0,l=n/m;
    for(int i=0,j=1;i<t;i++,j+=l){
        int ans=RMQ(j,j+l-1);
        sum+=ans;
    }
    if(sum>k) return 1;
    return 0;
}
int main(){
    int n,k;
    while(scanf("%d%d",&n,&k)!=-1){
        if(n<0&&k<0) break;
        for(int i=1;i<=n;i++) scanf("%d",&num[i]);
        RMQ_init(n);
        if(judge(n,n,k)==0) printf("-1\n");
        else{
            int le=1,ri=n;
            while(le<=ri){
                int mid=(le+ri)>>1;
                if(judge(n,mid,k)) ri=mid-1;
                else le=mid+1;
            }
            printf("%d\n",le);
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构,ACM,HDU,二分)