首先,选取子集的限制太宽了,子集似乎只能枚举,不是很好做。考虑加强限制条件:将“选取子集”的限制变为“选取子序列”的限制。在接下来的讨论中我们将会知道:将限制控制得更紧,问题也一定会有解。
现在我们需要求(A,B)的两个子序列,满足两者的和相等。显然可以前缀和,然后就不会做了qwq
考虑下面的算法:假定(sumlimits_{a in A} a < sumlimits_{b in B} b)(如果相等直接全选),设序列(A)前缀和为(sumA_i),序列(B)前缀和为(sumB_i)。
对于(n+1)个(sumA_i),在(sumB)中找到最小的大于等于它的元素(sumB_j),那么一定有(sumB_j - sumA_i in [0,n)),可能的(sumB - sumA)有(n)种,但是有(n+1)组(i,j)。
根据抽屉原理,一定会存在两组((i_1,j_1)(i_2,j_2)(i_1 > i_2))满足(sumB_{j_1} - sumA_{i_1} = sumB_{j_2} - sumA_{i_2}),即(sumB_{j_1} - sumB_{j_2} = sumA_{i_1} - sumA_{i_2})。这样我们就找到了一组可行解:在(A)中选择(A_x , x in (i_2 , i_1]),在(B)中选择(B_y , y in (j_2 , j_1])。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<cmath>
#include<random>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
}
#define PII pair < int , int >
#define st first
#define nd second
#define ll long long
const int MAXN = 1e6 + 7;
ll A[MAXN] , B[MAXN];
PII pos[MAXN];
signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
int N = read();
for(int i = 1 ; i <= N ; ++i)
A[i] = A[i - 1] + read();
for(int i = 1 ; i <= N ; ++i)
B[i] = B[i - 1] + read();
bool f = A[N] > B[N];
if(f) swap(A , B);
fill(pos , pos + N + 1 , PII(-1 , -1));
int p = 0;
for(int i = 0 ; i <= N ; ++i){
while(B[p] < A[i]) ++p;
if(pos[B[p] - A[i]] != PII(-1 , -1)){
PII t = pos[B[p] - A[i]];
if(!f){
printf("%d
" , i - t.first);
for(int j = t.first + 1 ; j <= i ; ++j)
printf("%d " , j);
printf("
%d
" , p - t.second);
for(int j = t.second + 1 ; j <= p ; ++j)
printf("%d " , j);
}
else{
printf("%d
" , p - t.second);
for(int j = t.second + 1 ; j <= p ; ++j)
printf("%d " , j);
printf("
%d
" , i - t.first);
for(int j = t.first + 1 ; j <= i ; ++j)
printf("%d " , j);
}
return 0;
}
else pos[B[p] - A[i]] = PII(i , p);
}
puts("-1");
return 0;
}