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 }