[CF 618F]Double Knapsack
转载请注明出处:http://danihao123.is-programmer.com/
我zzs就算掉光rating,R2爆炸,也不会做你们半道构造题!
啊构造题真好玩(一转)。
不妨钦定\(A\)中所有元素的和不大于\(B\)的。然后把两个集合按照任意顺序搞成一个序列,然后求出两者的前缀和\(SA\)和\(SB\)。
考虑对于0...n的\(SA_i\),找出\(SB\)中不大于他的数中最大的一个(不妨设为\(SB_j\)),可以发现有\(0\leq SA_i - SB_j\leq n - 1\)(不然\(j\)还能再大)。然后发现:我们处理的\(i\)和\(j\)的数对有\(n + 1\)组,但是\(SA_i - SB_j\)的取值却只有N种!也就是说一定存在\(i\neq i'\)且\(j\neq j'\)满足\(SA_i - SB_j = SA_{i'} - SB_{j'}\)。
我们找出两对这样的数对,移一下项就可以构造一组解了。
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cctype> #include <algorithm> #include <utility> #include <vector> using ll = long long; using pii = std::pair<int, int>; int n; void gen_S(int *arr, ll *S) { S[0] = 0LL; for(int i = 1; i <= n; i ++) { S[i] = (S[i - 1] + (ll(arr[i]))); } } const int maxn = 1000005; std::vector<pii> cs[maxn]; int main() { scanf("%d", &n); int *A = (int*)calloc(n + 1, sizeof(int)); int *B = (int*)calloc(n + 1, sizeof(int)); ll sum_A = 0LL, sum_B = 0LL; for(int i = 1; i <= n; i ++) { scanf("%d", &A[i]); sum_A += A[i]; } for(int i = 1; i <= n; i ++) { scanf("%d", &B[i]); sum_B += B[i]; } bool flip = false; if(sum_A > sum_B) { flip = true; std::swap(A, B); std::swap(sum_A, sum_B); } ll *SA = (ll*)calloc(n + 1, sizeof(ll));; ll *SB = (ll*)calloc(n + 1, sizeof(ll));; gen_S(A, SA); gen_S(B, SB); for(int i = 0; i <= n; i ++) { int j = std::upper_bound(SB, SB + n + 1, SA[i]) - SB - 1; ll val = SA[i] - SB[j]; cs[val].push_back(std::make_pair(i, j)); } int l1, r1, l2, r2; for(int i = 0; i < n; i ++) { if(cs[i].size() > 1) { int i1 = cs[i][0].first; int j1 = cs[i][0].second; int i2 = cs[i][1].first; int j2 = cs[i][1].second; if(i1 > i2) { std::swap(i1, i2); std::swap(j1, j2); } l1 = i1; r1 = i2; l2 = j1; r2 = j2; break; } } if(flip) { std::swap(l1, l2); std::swap(r1, r2); } printf("%d\n", r1 - l1); for(int i = l1 + 1; i <= r1; i ++) { if(i > l1 + 1) putchar(' '); printf("%d", i); } putchar('\n'); printf("%d\n", r2 - l2); for(int i = l2 + 1; i <= r2; i ++) { if(i > l2 + 1) putchar(' '); printf("%d", i); } putchar('\n'); free(A); free(B); free(SA); free(SB); return 0; }