UVA - 714 Copying Book
阿新 • • 發佈:2018-12-11
題目連結:
UVA - 714 Copying Book
題意:
給定一個m個數的序列,將這個序列分成k份連續子序列,要求子序列的最大值最小。
思路:
二分、貪心
這段序列不用再排序,先求出這段序列的和以及序列的最大值,然後從序列的最大值到序列的和開始二分查詢,找到劃分段數小於等於k的最小上限。
然後根據上面找到的上限,從最後開始往前劃分,因為前面找到的劃分段數可能小於k,這時候把原序列前面部分每個值劃分成一段,使最後的劃分數=k。
注意:
讀入的序列a[505],以及過程中的求和,區間等值記得開long long.
#include <iostream>
#include <cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll a[505],vis[505];
int main(int argc, char** argv) {
int Case;
scanf("%d",&Case);
while(Case--){
int m,k;
scanf("%d %d",&m,&k);
ll minv=-1;
ll total=0;//5*10^9
for(int i= 1;i<=m;i++){
scanf("%lld",&a[i]);
if(a[i]>minv) minv=a[i];
total+=a[i];
}
ll l=minv,r=total;
while(l<r){
ll mid=(l+r)>>1;
ll num=1,sum=0,flag=0;//初始化塊的大小很關鍵,num=1
for(int i=m;i>=1;i--){//從後往前劃分,使前面剩下的數儘量小
if(sum+a[i]>mid){
num++;
sum=a[i];
if(num>k){
flag=1;
l=mid+1;
break;
}
}else{
sum+=a[i];
}
}
if(!flag) r=mid;
}
ll sum=0,num=1;
memset(vis,0,sizeof(vis));
for(int i=m;i>=1;i--){
if(sum+a[i]>l){
vis[i]=1;
sum=a[i];
num++;
}else{
sum+=a[i];
}
if(k-num==i){//不夠分
for(int j=1;j<=i;j++){
vis[j]=1;
}
break;
}
}
for(int i=1;i<=m;i++){
if(i==1) printf("%d",a[1]);
else printf(" %d",a[i]);
if(vis[i]) printf(" /");
}
printf("\n");
}
return 0;
}
思路參考:
http://www.cnblogs.com/g0feng/archive/2012/10/16/2726726.html