• 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;
    }
  • 相关阅读:
    自学python day 10 函数的动态参数、命名空间、作用域
    老男孩 python 自学 打印05 dict 复习总结
    老男孩python 自学day09 函数开始
    今天
    day 03
    eclipse如何安装配置tomcat
    windows上配置maven环境
    如何创建ssh key使电脑和Github关联在一起
    怎么将本地文件上传到github
    使用git工具上传代码到github
  • 原文地址:https://www.cnblogs.com/gabo/p/2636559.html
Copyright © 2020-2023  润新知