• HDU 3486 Interviewe


    题目大意:给定n个数的序列,让我们找前面k个区间的最大值之和,每个区间长度为n/k,如果有剩余的区间长度不足n/k则无视之。现在让我们找最小的k使得和严格大于m。

    题解:二分k,然后求RMQ检验。

    ST算法:

    #include <cstdio> 
    #include <algorithm>
    #include <cstring> 
    using namespace std;  
    const int maxn=200010;    
    int d[maxn][30];  
    int a[maxn];   
    void init_rmq(int n){  
        for(int i=0;i<n;i++)d[i][0]=a[i];  
        for(int j=1;(1<<j)<=n;j++){  
            for(int i=0;i+(1<<j)-1<n;i++)  
            d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);  
        }  
    }   
    int query_rmq(int L,int R){  
        int k=0;  
        while(1<<(k+1)<=R-L+1)k++;  
        return max(d[L][k],d[R-(1<<k)+1][k]);  
    }  
    bool check(int len,int m,int t){  
        int sum=0;  
        for(int i=1;i<=t;i++){  
            sum+=query_rmq((i-1)*len,i*len-1);  
            if(sum>m)return true;  
        }  
        return false;  
    }  
    int main(){  
        int n,m;  
        while(~scanf("%d %d
    ",&n,&m)){  
            if(n<0||m<0)break;  
            int sum=0;  
            for(int i=0;i<n;i++){  
                scanf("%d",&a[i]);  
                sum+=a[i];  
            }  
            if(sum<=m){printf("-1
    ");continue;}  
            init_rmq(n);  
            int l=1,r=n,ans;  
            while(l<=r){  
                int mid=(l+r)>>1;  
                if(check(n/mid,m,mid)){  
                    ans=mid;  
                    r=mid-1;  
                }else l=mid+1;  
            }  
            printf("%d
    ",ans);  
        }  
        return 0;  
    }  
    

    暴力:

    #include <cstdio>  
    #include <cstring>  
    using namespace std;  
    const int maxn=200010;    
    int a[maxn];
    char c;    
    bool check(int len,int m,int t){  
        int x=-1,sum=0;  
        for(int i=0;i<t;i++){  
            for(int j=i*len+1;j<=(i+1)*len;j++)if(a[j]>x)x=a[j];
            sum+=x;if(sum>m)return true;x=-1;  
        }  
        return false;  
    }  
    void scan(int &x){
        while(c=getchar(),c<'0'||c>'9');x=c-'0';
        while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
    }
    int main(){  
        int n,m;  
        while(~scanf("%d%d
    ",&n,&m)){  
            if(n<0||m<0)break;  
            int sum=0;  
            for(int i=1;i<=n;i++){  
                scan(a[i]);  
                sum+=a[i];  
            }  
            if(sum<=m){printf("-1
    ");continue;}  
            int l=1,r=n,ans;  
            while(l<=r){  
                int mid=(l+r)>>1;  
                if(check(n/mid,m,mid)){  
                    ans=mid;  
                    r=mid-1;  
                }else l=mid+1;  
            }  
            printf("%d
    ",ans);  
        }  
        return 0;  
    }  
        令人惊讶的是暴力竟比ST快,因为复杂度少了一个log,所以做题时一定要多考虑,不要盲目码代码
  • 相关阅读:
    查看linux版本的三种常用方法
    CentOS和Redhat发行版linux内核版本的对应关系
    swift的异常处理:本质是错误信息的传递方式
    构建法则第一条:有什么材料做什么饭
    待解决问题 代码阅读
    iOS: 聊聊 Designated Initializer(指定初始化函数):NS_DESIGNATED_INITIALIZER
    整合与构建的能力是创造性思维的重要体现
    iOS网络缓存的系统实现是一个烂尾工程
    (动态)代理于HOOK的区别于关系
    iOS 网络缓存总结
  • 原文地址:https://www.cnblogs.com/forever97/p/3576982.html
Copyright © 2020-2023  润新知