hdu 3486 Interviewe RMQ

hdu 3486 Interviewe RMQ
//hdu 3486 Interviewe
//RMQ

//用RMQ预处理一下,然后进行枚举,具体看代码
//枚举要加优化,要不一样会超时

#define infile freopen("in.txt", "r", stdin);
#include <stdio.h>
#include <string.h>

#define INF (1<<30)
#define N 200005

int dp_max[20][N], log2[N];

inline int max(const int a, const int b)
{
    return a > b? a : b;
}

void rmq(int n)
{
    for(int i = 1; i <= log2[n]+1; ++i)//从第j个开始2^i个数,所以要减1
        for(int j = 1; j + (1<<i) - 1 <= n; ++j)//这里中间那个一定要减1,wa了好多次
            dp_max[i][j] = max(dp_max[i-1][j], dp_max[i-1][j+(1<<(i-1))]);
    //j+(1<<i)-1 减1表示从第j个起的2^i个,包括j所以要减 1
}

int get_max(int from, int to)
{
    int index = log2[to-from+1];
    return max(dp_max[index][from], dp_max[index][to-(1<<index)+1]);
}

int find(int n, int low)    //枚举
{
    int pre_num = -1, pre_tot = -1, pre_sum;
    for(int i = 1; i <= n; ++i) //分成i组
    {
        int num = n / i;    //每组num个
        int sum = num * i;  //总的多少人
        int tot = 0;
        if(num == pre_num)  //如果和前一次一样则从前一次继续累加即可
        {
            tot = pre_tot;
            for(int j = pre_sum + num; j <= sum; j+= num)
            {
                tot += get_max(j - num + 1, j);
                if(tot > low)
                    return i;
            }
            pre_tot = tot;
            pre_sum = sum;
        }
        else
        {
            for(int j = num; j <= sum; j += num)
            {
                tot += get_max(j-num+1, j);
                if(tot > low)
                    return i;
            }
            pre_num = num;
            pre_tot = tot;
            pre_sum = sum;
        }
    }
    return -1;
}

int main()
{
    //infile
    int n, low;
    for(int i = 2; i < N; ++i)
        log2[i] = (i&(i-1)) == 0 ? log2[i-1]+1 : log2[i-1];
    while(scanf("%d%d", &n, &low), n > 0 || low > 0)
    {
        memset(dp_max, 0, sizeof(dp_max));
        for(int i = 1; i <= n; ++i)
            scanf("%d", &dp_max[0][i]);

        rmq(n);

        printf("%d\n", find(n, low));

//一下二分是错的 wa了,下面这组数据答案应该是2,可以卡死
//但别人这组数据过不了也a了,估计我的二分写错了
//10 1500
//1 1 1 1 1000 1000 1 1 1 1

//        int l = 1, h = n;
//        bool flag = false;
//        while(l < h)
//        {
//            int mid = l + (h-l)/2;
//            int num = n / mid, sum = 0;
//            for(int i = 0; i < mid; ++i)
//                sum += get_max(i*num+1, (i+1)*num);
//            if(sum > low)
//            {
//                flag = true;
//                h = mid;
//            }
//            else
//                l = mid + 1;
//        }
//        if(l == h && flag == true)
//            printf("%d\n", l);
//        else
//            puts("-1");
    }
    return 0;
}

 

二杰的二分
#include <stdio.h>
#include <string.h>

const int N = 200005;

int log2[N];
int rmqMax[N][20];//表示从i到i+(2^j)-1最大的值

void init()
{
    log2[1] = log2[0] = 0;
    for(int i = 2; i < N; ++i)
    {
        log2[i] = log2[i-1];
        if(((i-1)&i) == 0)
            log2[i]++;
    }
}

inline int max(const int a, const int b)
{
    return a > b? a : b;
}

inline int query(int a, int b)
{
    int k = log2[(b-a)+1]+1;
    return max(rmqMax[a][k-1], rmqMax[b-(1<<(k-1))+1][k-1]);
}

int getAns(int key, int step)
{
    int ans = 0;
    for(int i = 1; i+step-1 <= step*key; i += step)
    {
        ans += query(i, i+step-1);
    }
    return ans;
}

int binaryFind(int left, int right, int k, int n)
{
    int tt = 0;
    for(int i = 1; i <= n; ++i)
        tt += rmqMax[i][0];
    if(tt <= k)
        return -1;
    int mid;
//对组数二分,不是对每组多少人二分
    while(left != right)
    {
        mid = (left+right)/2;
        int num = n/mid;

        int ans = getAns(mid,num);

        if(ans > k)
            right = mid;
        else
            left = mid+1;
    }

    return right;
}

int main(void)
{
   // comein
    int n, k;
    init();
    while(scanf("%d%d", &n, &k) == 2 && n>0 && k>0)
    {
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d", &rmqMax[i][0]);
        }
        for(int j = 1; j < 20; ++j)
        {
            for(int i = 1; i+(1<<(j-1)) <= n; ++i)
            {
                rmqMax[i][j] = max(rmqMax[i][j-1], rmqMax[i+(1<<(j-1))][j-1]);
            }
        }
//        int a, b;
//        while(scanf("%d%d", &a, &b) == 2)
//        {
//            int ans = query(a, b);
//            printf("%d\n", ans);
//        }
        int ans = binaryFind(1, n, k, n);
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2012-08-13 16:03  gabo  阅读(404)  评论(0编辑  收藏  举报