本题做法
- 贪心策略+二分答案。
思路
贪心策略:让越往前的同学抄的书尽可能少,后面的尽可能多。
使用二分答案法,详细讲解\(check\)函数的写法。
\(check\)函数
传入一个参数\(x\),代表当前二分出的预定最短复制时间。从第\(m\)本书到第1本书反向遍历,若当前同学再抄第\(i\)本书后超出\(x\),则更换下一个同学抄书。最后记得特判一个最后的同学是否能够在\(x\)时间内抄完书。
代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long longusing namespace std;const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const int N = 505;int m, k, s, p[N], r[N][2], ans;bool check(int x) {int now = k, cnt = 0;for (int i = m; i >= 1; i--) {cnt += p[i];if (cnt > x) {cnt = p[i];now--;}if (now <= 0)return 0;}if (cnt > x)return 0;return 1;
}void print() {int now = k, cnt = 0, beg = m;for (int i = m; i >= 1; i--) {cnt += p[i];if (cnt > ans) {cnt = p[i];r[now][1] = i + 1;r[now][2] = beg;beg = i;now--;}}r[1][1] = 1;r[1][2] = beg;for (int i = 1; i <= k; i++)cout << r[i][1] << " " << r[i][2] << endl;
}int main() {cin >> m >> k;for (int i = 1; i <= m; i++) {cin >> p[i];s += p[i];}int l = 0, r = s + 1;while (l + 1 < r) {int mid = (l + r) >> 1;if (check(mid)) {r = ans = mid;} elsel = mid;}print();return 0;
}