HDU 3486 Interviewe【二分+rmq】

题意: 给出 n 个序列,要求把它分成长度相等的m份,多余的去掉,要求每份的最大值之和大于 k。

         问最少要分成多少份。

分析: 二分区间,用rmq预处理出区间最大值。

#include <stdio.h>
#include <string.h>
#include <math.h>
#define max(a,b)(a)>(b)?(a):(b)
#define maxn 200005
int val[maxn];
int dp[maxn<<1][20];
int k,n;
void makermq()
{
    int i, j;
    for(i = 1; i <= n; i++)
        dp[i][0] = val[i];
    for(j = 1; (1<<j)<=n; j++)
        for(i = 1;i+(1<<j)-1<=n; i++)
            dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r)
{
    int k = (int)(log((r-l+1)*1.0)/log(2.0));
    return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
int ok(int m)
{
    int en = n,t,sum,i,mod;
    if(n%m!=0)
        en-=n%m;
    mod = n/m;
    t = sum = 0;
    for(i = mod; i <= en; i+=mod)
    {
        sum += rmq(i-mod+1,i);
        if(sum > k)
            return 1;
    }
    return sum>k;
}
inline bool scan_d(int &num)  
{
        char in;
        bool IsN=false;
        in=getchar();
        if(in==EOF) return false;
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();
        if(in=='-'){ IsN=true;num=0;}
        else num=in-'0';
        while(in=getchar(),in>='0'&&in<='9'){
                num*=10,num+=in-'0';
        }
        if(IsN) num=-num;
        return true;
}
int main()
{
    int i;
    int l, r, mid, res;
    while(scanf("%d %d",&n, &k)!=EOF)
    {
        if(n<0&&k<0)
            break;
        for(i = 1; i <= n; i++)
            scan_d(val[i]);
        makermq();
        l = 1;
        r = n;
        res = -1;
        while(l<=r)
        {
            mid = (l+r)>>1;
            if(ok(mid)){
                res = mid;
                r = mid-1;
            }
            else l = mid+1;
        }
        printf("%d\n",res);
    }
    return 0;
}

 

posted @ 2012-10-25 07:41  'wind  阅读(147)  评论(0编辑  收藏  举报