【uva 714】Copying Books(算法效率--二分+贪心)

题意:将1个含N个正整数的序列划分成K个连续的子序列,使每段的和的最大值尽量小,问字典序最小的划分方案。

解法:由于是连续的数的“最大值最小”,便可想到二分每段的最大值,若这时可分成<=K段,则这个最大值成立,再继续二分。

输出方案需要用到贪心策略, 先从后往前贪心求得最小划分的段数M,若M不足K,则直接使K-M个数单独划分为一段,保证字典序最小。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 const int N=510,D=(int)1e7+10;//N*D long long
 7 typedef long long LL;
 8 int a[N],v[N];
 9 int n,k;
10 
11 int check(LL x)
12 {
13     LL t=1,h=0;
14     for (int i=1;i<=n;i++)
15     {
16       h+=a[i];
17       if (h>x) h=a[i],t++;
18     }
19     return t<=k;
20 }
21 int main()
22 {
23     int T;
24     scanf("%d",&T);
25     while (T--)
26     {
27       long long h=0,mx=0;
28       scanf("%d%d",&n,&k);
29       for (int i=1;i<=n;i++)
30         scanf("%d",&a[i]),h+=a[i],mx=mx>a[i]?mx:a[i];
31       LL l=mx,r=h,mid,ans=1<<30;
32       while (l<=r)
33       {
34         mid=(l+r)>>1;
35         int tmp=check(mid);
36         if (tmp) ans=mid,r=mid-1;
37         else l=mid+1;
38       }
39       int e=1; h=0;
40       for (int i=n;i>=1;i--)
41       {
42         h+=a[i], v[i]=0;
43         if (h>ans) h=a[i],e++,v[i]=1;
44       }
45       h=0;
46       for (int i=1;i<=n;i++)
47       {
48         printf("%d",a[i]);
49         if (v[i]) printf(" /");
50         else if (h<k-e) printf(" /"),h++;
51         if (i<n) printf(" ");
52       }
53       printf("\n");
54     }
55     return 0;
56 }

 

posted @ 2016-10-31 22:22  konjac蒟蒻  阅读(269)  评论(0编辑  收藏  举报