UVA 714 Copying Books (二分)

来源:互联网 发布:xbox你的网络尚未设置 编辑:程序博客网 时间:2024/05/16 15:49

题意:把一个包含m个正整数的序列划分成k个非空的连续子序列,使得每个正整数恰好属于一个序列。设第i个序列的和为S(i),要找所有S(i)的最大值尽量小。

如有多解,S(1)应尽量小。如果仍有多解,S(2)应尽量小,以此类推。

思路:通过二分找到一个最小x ,使得对任意S(i)<=x,时间复杂度O(logM),再通过从右到左的扫描即可完成。

AC代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 500+10;typedef long long LL;int m,k,f[maxn];int solve(LL M){LL done = 0;int cnt = 0;for(int i = 0; i < m; i++){if(done + f[i] > M){done = f[i];cnt++ ;}else done += f[i];}return cnt+1 ;}int scribe[maxn];void print(LL l){memset(scribe,0,sizeof(scribe));LL done = 0;int remain = k - 1;for(int i = m-1; i >= 0; i--){if(done + f[i] > l || i + 1 <= remain){done = f[i];scribe[i] = 1;remain--;}else done += f[i];}for(int i = 0; i < m-1; i++){printf("%d ",f[i]);if(scribe[i]) printf("/ ");}printf("%d\n",f[m-1]);}int main(){int T;scanf("%d",&T);while(T--){    scanf("%d%d",&m,&k);    int Max = 0;    LL tol = 0;    for(int i = 0; i < m; i++){    scanf("%d",&f[i]);    Max = max(Max,f[i]);    tol += f[i];}LL l = Max ,r = tol;while(l < r){LL M = l + (r - l)/2;if(solve(M) <= k)r = M;else l = M + 1;}print(l);}return 0;}




原创粉丝点击