• hdu3486Interviewe(二分是错的)(ST算法RMQ + 判定上下界枚举)


    题目大意是找最小的m使得前m段中每一段的最大值相加严格大于k,每一段长度为[n/m](n/m向下取整,多余的后半部分部分n-m*[n/m]不要)

    先给一段我一开始的思路,和网上许多题解思路一样,但其实是有错误的。二分答案+RMQ (RMQ部分也可以用线段树)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 2e5 + 5;
    const int inf = 0x3f3f3f3f;
    int f[maxn][30];
    int n, k, m, v[maxn];
    int mx, mi, tot;
    inline int max( int a,int b ){
        return a>b ? a:b;
    }
    
    inline int min( int a, int b ){
        return a<b ? a:b;
    }
    
    inline void ST_make(){
        for( int i=1; i<=n; i++ )
            f[i][0] = v[i];
        for( int j=1; (1<<j)<=n; j++ )
            for( int i=1; i<=n; i++ )
                f[i][j] = max( f[i][j-1], f[i+(1<<(j-1))][j-1] );
    }
    
    inline int ST_query( int l, int r ){
        int k = log(r-l+1)/log(2);
        return max( f[l][k], f[r-(1<<k)+1][k]);
    }
    
    int main(){
        while( ~scanf("%d%d", &n, &k) ){
            if( n<0 && k<0 ) break;
            memset( f, 0, sizeof(f) );
            mx = -inf; mi = inf;
            tot = 0;
            for( int i=1; i<=n; i++ ){
                scanf("%d", &v[i]);
                tot += v[i];
                mx = max( v[i], mx );
                mi = min( v[i], mi );
            }
            if( mx>k ) {puts("1
    "); continue;}
            else if( tot<=k ) {puts("-1
    "); continue;}
            ST_make();
            mx = mx ? mx:1;
            mi = mi ? mi:1;
            int l = k/mx, r = min( n, k/mi+1 ), sum;        //判断上下界,节省时间
            while( l<r ){
                sum = 0;
                int mid = l+r>>1;            //这个地方不能直接用m = l+r>>1
                int t = n/mid;
                int tmp = 1;
                int d = t*mid;
                while( tmp<d){
                    sum += ST_query( tmp, tmp+t-1 );
                    tmp += t;
                }
                if( sum>k ){            //符合条件再令m = mid;
                    r = mid;
                    m = mid;
                }
                else l = mid+1;
            }
            printf("%d
    ", m);
        }
    
        return 0;
    }
    View Code

    思路都写好了,然鹅是错的。。。

    给一份Discuss里dalao给的卡二分的数据

    10 1500
    1 1 1 1 1000 1000 1 1 1 1
    很明显 答案是2 但是输出我记得好像是7
    所以换了暴力枚举的思路,上代码
    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 2e5 + 5;
    const int inf = 0x3f3f3f3f;
    int f[maxn][30];
    int n, k, m, v[maxn];
    int mx, mi, tot;
    inline int max( int a,int b ){
        return a>b ? a:b;
    }
    
    inline int min( int a, int b ){
        return a<b ? a:b;
    }
    
    inline void ST_make(){
        for( int i=1; i<=n; i++ )
            f[i][0] = v[i];
        int t = log(n)/log(2)+1;
        for( int j=1; j<t; j++ )
            for( int i=1; i+(1<<j)-1<=n; i++ )
                f[i][j] = max( f[i][j-1], f[i+(1<<(j-1))][j-1] );
    }
    
    inline int ST_query( int l, int r ){
        int k = log(r-l+1)/log(2);
        return max( f[l][k], f[r-(1<<k)+1][k]);
    }
    
    int main(){
        while( ~scanf("%d%d", &n, &k) ){
            if( n<0 && k<0 ) break;
            mx = -inf; mi = inf;
            tot = 0;
            for( int i=1; i<=n; i++ ){
                scanf("%d", &v[i]);
                tot += v[i];
                mx = max( v[i], mx );
                mi = min( v[i], mi );
            }
            if( tot<=k ){
                printf("-1
    ");
                continue ;
            }
            ST_make();
            mx = mx ? mx:1;
            mi = mi ? mi:1;
            int l = k/mx, r = (k/mi+1, n);        //判定上下界,节省时间(好像判了上界r还慢了。。)
            if(l==0) l = 1;               
            bool ok = 0;
            for( m=l; m<=r; m++ ){
                int sum = 0;
                int t = n/m;
                int d = t*m;
                for( int i=1; i<=d; i+=t )            //这个地方要等于号,可举例n = m时 若i<d为判定条件则不能进行,卡了一年
                    sum += ST_query( i, i+t-1 );
                if( sum>k ){
                    ok = 1;
                    break;
                }
            }
            if(ok) printf("%d
    ", m);
            else printf("-1
    ");
        }
        return 0;
    }

  • 相关阅读:
    动态规划入门到熟悉,看不懂来打我啊
    git 查看当前仓库地址以及设置新的仓库地址
    数字与字符串系列教材 (三)- Java Math类常用方法
    数字与字符串系列教材 (三)- Java Math类常用方法
    数字与字符串系列教材 (二)- Java中把数字转换为字符串,字符串转换为数字
    数字与字符串系列教材 (二)- Java中把数字转换为字符串,字符串转换为数字
    数字与字符串系列教材 (一)- Java中基本类型的装箱和拆箱
    数字与字符串系列教材 (一)- Java中基本类型的装箱和拆箱
    接口与继承系列教材 (十)- Java 内部类详解
    接口与继承系列教材 (十)- Java 内部类详解
  • 原文地址:https://www.cnblogs.com/WAautomaton/p/10869656.html
Copyright © 2020-2023  润新知