您的位置:首页 > 运维架构

UVA 714 Copying Books(二分+贪心)

2017-02-26 00:24 351 查看
大体题意:

给你n 个数,要求分成m份,使得m份中的最大值最小,要求打印解,如果多解,要求第一份最小,其次第二份最小,,依次类推。

思路:

最大值最小,肯定是二分了。

我们直接二分最大值,找一个最小的答案x。

然后我们划分n 个数,因为越往前越小,所以肯定从后向前枚举。

然后第i 个数要不要划分的话,有两个依据,当前和超过了x  或者 剩下的可以切的刀数不足 要求的刀数,那么就必须划分了。

令pos[i] = 1 表示第i 个数后面要划分  0 表示不划分,这样打印解就好了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
using namespace std;
typedef long long LL;

int n, m;

const int maxn = 500 + 7;
const int inf = 0x3f3f3f3f;

int pos[maxn], a[maxn];
LL sum_pre[maxn];

vector<LL>v;

int judge(LL mid){
int cur = 0;
LL sum = 0;
for (int i = 1; i <= n; ++i){
sum += a[i];
if (sum < mid) continue;
if (sum > mid){
i--;
cur++;
sum = 0;
}
else if (sum == mid){
cur++;
sum = 0;
}
}
if (sum) cur++;
return cur;
}

void solve(LL L,LL R){
LL mid;
LL bet = inf;
while(L <= R){
mid = L + R >> 1LL;
int ans = judge(mid);
if (ans <= m) {
R = mid-1;
bet = Min(bet,mid);
}
else L = mid+1;
}

LL sum = a
;
int remain = m-1;

for (int i = n-1; i > 0; --i){
if (sum + a[i] > bet || i <= remain ) {
pos[i] = 1;
remain--;
sum = a[i];
}
else {
pos[i] = 0;
sum += a[i];
}
}
pos
= 0;
printf("%d",a[1]);
for (int i = 2; i <= n; ++i){
if (pos[i-1])printf(" / ");
else printf(" ");
printf("%d",a[i]);
}
puts("");
}

int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n, &m);
LL sum = 0;
int MAX = -inf;
for (int i = 1; i <= n; ++i){
scanf("%d",a+i);
sum += a[i];
MAX = Max(MAX,a[i]);
// sum_pre[i] = sum_pre[i-1] + (LL)a[i];
}
a[n+1] = 0;
solve(MAX,sum);
}

return 0;
}

/**

2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100

out:
100 200 300 400 500 / 600 700 / 800 900
100 / 100 / 100 / 100 100
**/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: