UVA 714

来源:互联网 发布:淘宝草根vr工厂 编辑:程序博客网 时间:2024/06/03 04:20

  挺好的一道题,题意是说划分一个有m个元素的序列成k段,使各段之和的最大值最小,我们枚举这个最小的最大值,但题目所给范围比较大,最高能到500亿,所以选择二分法枚举,输出的时候要求尽可能往前划分,那么我们从后向前贪心的划分即可,可以说是二分和贪心结合的非常好的题目,值得好好体会一下。具体还有一些小的优化,直接在注释中给出。

#include <iostream>#include <cstdio>using namespace std;long long num[510],sum[510];bool is[510];int m,k,size;bool yes(long long ans){int total=0,pre=0;for(int i=1;i<=m;){while(i<=m&&(sum[i]-sum[pre])<=ans) i++;total++;pre=i-1;}if(total<=k) return true;else return false;}int main(){int T;scanf("%d",&T);while(T--){scanf("%d%d",&m,&k);sum[m+1]=sum[0]=0;int Max=0;for(int i=1;i<=m;i++){scanf("%lld",num+i);if(num[i]>Max) Max=num[i];//最小的最大值一定大于等于整个序列中的最大值sum[i]=sum[i-1]+num[i];//判断是会比较快is[i]=false;}long long low=Max,high=sum[m];//最小的最大值一定小于等与整个序列的和while(low<high){long long mid=(low+high)>>1;if(yes(mid)) high=mid;//找到最小的可满足条件的值else low=mid+1;}long long total=0;k--;for(int i=m;i>0;i--){if((num[i]+total)>low){is[i]=true;total=num[i];k--;}else total+=num[i];//这个if很关键,解释现在加上当前数字仍比low小,但我们必须满足划分为k段if(i==k){for(;i>0;i--) is[i]=true;break;}}for(int i=1;i<=m;i++){cout<<num[i];if(i==m) cout<<endl;else cout<<" ";if(is[i]) cout<<"/ ";}}return 0;}


 

0 0
原创粉丝点击