UVA714 Copying books 题解报告

题目传送门

【题目大意】

【思路分析】

发现是Luogu P1281 书的复制原题……

思路是二分答案,二分出最小的$max$值之后判断是否合法,即判断是否恰好能分成$k$组。

最后的输出有点麻烦,因为要保证前面的人分到的尽量少,所以要倒序贪心一下,详见代码。

【代码实现】

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define g() getchar()
 7 #define rg register
 8 #define go(i,a,b) for(rg int i=a;i<=b;i++)
 9 #define back(i,a,b) for(rg int i=a;i>=b;i--)
10 #define db double
11 #define ll long long
12 #define il inline
13 #define pf printf
14 #define mem(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 int fr(){
17     int w=0,q=1;
18     char ch=g();
19     while(ch<'0'||ch>'9'){
20         if(ch=='-') q=-1;
21         ch=g();
22     }
23     while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g();
24     return w*q;
25 }
26 const int M=502;
27 int n,m,k;
28 ll a[M];
29 bool start[M];//start数组记录当前这个数后面是否要划分
30 il bool check(rg ll mid){
31     rg int t=1;
32     rg ll sum=0;
33     go(i,1,m)
34         if(sum+a[i]<=mid) sum+=a[i];
35         else t++,sum=a[i];
36     return t<=k;
37 }
38 il void put(rg ll x){//倒序贪心输出
39     rg ll sum=0;rg int t=k;mem(start,0);
40     back(i,m,1){
41         if(t>i) start[i]=1,t--;//如果前面恰好能1个1组那就直接划分
42         else
43             if(sum+a[i]<=x) sum+=a[i];//保证每个区间的和不能大于最大值
44             else start[i]=1,t--,sum=a[i];//不满足条件了就划分
45     }
46     pf("%lld",a[1]);if(start[1]) pf(" /");
47     go(i,2,m){
48         pf(" %lld",a[i]);
49         if(start[i]) pf(" /");
50     }puts("");
51     return;
52 }
53 int main(){
54     n=fr();
55     while(n--){
56         m=fr();k=fr();
57         rg ll r=0,l=0;
58         go(i,1,m) a[i]=fr(),r+=a[i],l=max(l,a[i]);
59         while(l<r){
60             rg ll mid=(l+r)>>1;
61             if(check(mid)) r=mid;
62             else l=mid+1;
63         }put(l);
64     }
65     return 0;
66 }
代码戳这里
原文地址:https://www.cnblogs.com/THWZF/p/11386996.html