题意:按顺序给你N个数,将这N个数分成连续的M段,使得这M段每段的和中的最大值最小,输出最小值(1<=N<=100000,1<=M<=N,每个数在1到10000之间),如果有多种可能的话,尽量在前面进行划分。
思路:
1、由于函数具有单调性的特征,因此可以用二分枚举的办法去实现它,这与POJ3258有非常相似的地方,但这里不需要排序。
2、输出的时候需要用到贪心的思想,既尽量往前划分。
3、大概的思路就是二分枚举求得满足题意的最大值之后,然后以这个最大值通过从后往前的方式划分成段,如果剩余可划分段与i+1的值相等(尽量靠前),则将剩余的段往前划分,具体实现可以用一个标记数组use表示是否划分。
5、注意high_bound可能超int,所以需要long long 来存。
CODE:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 510;
int a[MAXN], use[MAXN];
long long low_bound, high_bound;
int n, m;
void init()
{
low_bound = -1;
high_bound = 0;
memset(use, 0, sizeof(use));
}
int solve(int mid)
{
int sum = 0, group = 1;
for(int i = n-1; i >= 0; i--)
{
if(sum + a[i] > mid)
{
sum = a[i];
group++;
if(group > m) return 0;
}
else sum += a[i];
}
return 1;
}
void print(int high_bound)
{
int group = 1, sum = 0;
for(int i = n-1; i >= 0; i--)
{
if(sum + a[i] > high_bound)
{
use[i] = 1;
sum = a[i];
group++;
}
else sum += a[i];
if(m-group == i+1)
{
for(int j = 0; j <= i; j++)
use[j] = 1;
break;
}
}
for(int i = 0; i < n-1; i++)
{
printf("%d ", a[i]);
if(use[i]) printf("/ ");
}
printf("%d\n", a[n-1]);
}
int main()
{
int T;
scanf("%d%*c", &T);
while(T--)
{
init();
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
if(low_bound < a[i]) low_bound = a[i];
high_bound += a[i];
}
long long x = low_bound, y = high_bound;
while(x <= y)
{
long long mid = x+(y-x)/2;
if(solve(mid)) y = mid-1;
else x = mid+1;
}
print(x);
}
return 0;
}
#include <cstdlib>
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 510;
int a[MAXN], use[MAXN];
long long low_bound, high_bound;
int n, m;
void init()
{
low_bound = -1;
high_bound = 0;
memset(use, 0, sizeof(use));
}
int solve(int mid)
{
int sum = 0, group = 1;
for(int i = n-1; i >= 0; i--)
{
if(sum + a[i] > mid)
{
sum = a[i];
group++;
if(group > m) return 0;
}
else sum += a[i];
}
return 1;
}
void print(int high_bound)
{
int group = 1, sum = 0;
for(int i = n-1; i >= 0; i--)
{
if(sum + a[i] > high_bound)
{
use[i] = 1;
sum = a[i];
group++;
}
else sum += a[i];
if(m-group == i+1)
{
for(int j = 0; j <= i; j++)
use[j] = 1;
break;
}
}
for(int i = 0; i < n-1; i++)
{
printf("%d ", a[i]);
if(use[i]) printf("/ ");
}
printf("%d\n", a[n-1]);
}
int main()
{
int T;
scanf("%d%*c", &T);
while(T--)
{
init();
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
if(low_bound < a[i]) low_bound = a[i];
high_bound += a[i];
}
long long x = low_bound, y = high_bound;
while(x <= y)
{
long long mid = x+(y-x)/2;
if(solve(mid)) y = mid-1;
else x = mid+1;
}
print(x);
}
return 0;
}