题目链接:http://acm.ustc.edu.cn/ustcoj/problem.php?id=1274
很典型的题目:n个数分成m段使所有分成的段的最大值最小(每段非空),最后输出方案,要求前面的划分越小越好。
把所有数加起来的sum作为最值大了,但是我们有了上界,之后二分猜答案。
关键是输出方案,是个贪心算法,后面能放的尽量放,但要保证至少前面每段一个。。。调了一个下午。。。。。代码能力太弱了,知道思路都写不出来,特此铭记。。。激励自己。。。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<algorithm>
#pragma waerning (disable : 4996)
#define LL long long
#define mem(a) meeset(a, 0, sizeof(a))
using namespace std;
int a[550], b[550], st[500], en[500];
int ch(int x, int n, int m)
{
int i = 0, j, k, st = 0, s = 0;
for (j = st; j < n;)
{
while (j < n && s + a[j] <= x)
s += a[j++];
if (j < n && a[j] > x) return 0;
st = j, s= 0, i++;
}
if (i <= m) return 1;
return 0;
}
int bs(int s, int e, int n, int m)
{
int mid, i, j, k;
mid = (s + e) / 2;
if (m == 1 && e == 2) return 1;
if (s + 1 >= e) return e;
else
{
k = ch(mid, n, m);
if (k == 0) return bs(mid, e, n, m);
else return bs(s, mid, n, m);
}
}
int main()
{
int t, n, m, i, j, k, max, sum;
cin >> t;
while (t--)
{
sum = max = 0;
cin >> n >> m;
for (i = 0; i < n; ++i) cin >> a[i], sum += a[i];
max = bs(1, sum + 1, n, m);
cout << max << endl;
k = m;
for (i = 0; i < n; ++i) b[i + 1] = a[i];
for (i = n, sum = 0; i >= 1;)
{
if (i > m)
{
if (sum + b[i] > max)
{
st[m] = i + 1;
m--;
en[m] = i;
sum = 0;
}
else if (sum + b[i] == max)
{
st[m] = i;
m--;
en[m] = i - 1;
sum = 0;
i--;
}
else
{
sum += b[i];
i--;
}
}
else if (i == m)
{
if (sum == 0)
{
for (j = 1; j <= i; ++j)
st[j] = en[j] = j;
break;
}
else if (sum + b[i] > max)
{
st[m] = i + 1;
en[m - 1] = i;
sum = 0;
m--;
}
else if (sum + b[i] <= max)
{
st[m] = i;
en[m - 1] = i - 1;
sum = 0;
m--;
i--;
}
}
}
st[1] = 1, en[k] = n;
for (i = 1; i <= k; ++i)
cout << st[i] << ' ' << en[i] << endl;
}
return 0;
}