CF618F Double Knapsack
博客食用更佳
CF618F Double Knapsack
\texttt{Description}
题面很友好,略。
\texttt{Solution}
看到这种题没什么思路,我首先就输出了 -1
,结果
于是我大胆猜想,每一个都有解,并且在两个集合中都是一个子段。
尝试证明。
设
不妨设
定义
容易发现,
移项得
因为
根据抽屉原理,可知至少有两个
假设
移项可得
此时一组答案就可以是
至于如何快速求出每个
时间复杂度:
\texttt{Code}
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
template <typename T>
inline void Swap (T &x, T &y) {x ^= y ^= x ^= y;}
int a[1000005], b[1000005], c[1000005], id[1000005][2];
ll suma[1000005], sumb[1000005], flag[1000005];
int main () {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), suma[i] = suma[i - 1] + 1ll * a[i];
for (int i = 1; i <= n; i++)
scanf("%d", &b[i]), sumb[i] = sumb[i - 1] + 1ll * b[i];
bool isSwap = false;
if (suma[n] > sumb[n]) {
isSwap = true;
for (int i = 1; i <= n; i++)
Swap(a[i], b[i]), Swap(suma[i], sumb[i]);
}
int j = 0, al, ar, bl, br;
for (int i = 0; i <= n; i++) {
for (; suma[i] >= sumb[j] && j <= n; j++);
j--;
if (flag[suma[i] - sumb[j]]) {
al = id[suma[i] - sumb[j]][0] + 1;
ar = i;
bl = id[suma[i] - sumb[j]][1] + 1;
br = j;
break;
}
flag[suma[i] - sumb[j]] = true;
id[suma[i] - sumb[j]][0] = i;
id[suma[i] - sumb[j]][1] = j;
}
if (isSwap)
Swap(al, bl), Swap(ar, br);
printf("%d\n", ar - al + 1);
for (int i = al; i <= ar; i++)
printf("%d ", i);
printf("\n%d\n", br - bl + 1);
for (int i = bl; i <= br; i++)
printf("%d ", i);
return 0;
}