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",&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\n");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\n",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",&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\n");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\n",ans);  

    }  

    return 0;  

}  
 令人惊讶的是暴力竟比ST快,因为复杂度少了一个log,所以做题时一定要多考虑,不要盲目码代码

 

 

 

你可能感兴趣的:(interview)