[关闭]
@ZCDHJ 2019-10-31T12:01:30.000000Z 字数 1504 阅读 430

Codeforces618F Double Knapsack

未分类


很妙的一道题。

考虑加强限制,将子集变为连续子序列。假设 ,那么对于任意一个 的前缀和 都能找到一个最小的 ,此时因为数字的值域是 ,一定有 ,因为有 而值域里只有 个数字,根据鸽巢原理一定能找到一组 ,满足 ,移项得 也就是题目要求的序列。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. typedef long long LL;
  5. const int MAXN = 1e6;
  6. int n;
  7. int pos[2][MAXN | 1];
  8. LL a[MAXN | 1], b[MAXN | 1];
  9. inline int read() {
  10. register int x = 0;
  11. register char ch = getchar();
  12. while (!isdigit(ch)) ch = getchar();
  13. while (isdigit(ch)) {
  14. x = x * 10 + ch - '0';
  15. ch = getchar();
  16. }
  17. return x;
  18. }
  19. int main() {
  20. freopen("code.in", "r", stdin);
  21. freopen("code.out", "w", stdout);
  22. n = read();
  23. for (int i = 1; i <= n; ++i) {
  24. a[i] = a[i - 1] + read();
  25. // printf("i=%d a[i]=%d b[i]=%d\n", i, a[i], b[i]);
  26. }
  27. for (int i = 1; i <= n; ++i) {
  28. b[i] = b[i - 1] + read();
  29. }
  30. bool flag = false;
  31. if (a[n] > b[n]) std::swap(a, b), flag = true;
  32. memset(pos, -1, sizeof(pos));
  33. pos[0][0] = 0;
  34. pos[1][0] = 0;
  35. for (int i = 1, p = 0; i <= n; ++i) {
  36. while (b[p] < a[i]) ++p;
  37. if (pos[0][b[p] - a[i]] != -1) {
  38. if (flag == false) {
  39. printf("%d\n", i - pos[0][b[p] - a[i]]);
  40. for (int j = pos[0][b[p] - a[i]] + 1; j <= i; ++j) printf("%d ", j);
  41. printf("\n");
  42. printf("%d\n", p - pos[1][b[p] - a[i]]);
  43. for (int j = pos[1][b[p] - a[i]] + 1; j <= p; ++j) printf("%d ", j);
  44. printf("\n");
  45. } else {
  46. printf("%d\n", p - pos[1][b[p] - a[i]]);
  47. for (int j = pos[1][b[p] - a[i]] + 1; j <= p; ++j) printf("%d ", j);
  48. printf("\n");
  49. printf("%d\n", i - pos[0][b[p] - a[i]]);
  50. for (int j = pos[0][b[p] - a[i]] + 1; j <= i; ++j) printf("%d ", j);
  51. printf("\n");
  52. }
  53. return 0;
  54. }
  55. pos[0][b[p] - a[i]] = i;
  56. pos[1][b[p] - a[i]] = p;
  57. }
  58. return 0;
  59. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注