【题目】
Description
You are given two multisets A and B. Each multiset has exactly n integers each between 1 and n inclusive. Multisets may contain multiple copies of the same number.
You would like to find a nonempty subset of A and a nonempty subset of B such that the sum of elements in these subsets are equal. Subsets are also multisets, i.e. they can contain elements with equal values.
If no solution exists, print - 1. Otherwise, print the indices of elements in any such subsets of A and B that have the same sum.
Input
The first line of the input contains a single integer n (1 ≤ n ≤ 1 000 000) — the size of both multisets.
The second line contains n integers, denoting the elements of A. Each element will be between 1 and n inclusive.
The third line contains n integers, denoting the elements of B. Each element will be between 1 and n inclusive.
Output
If there is no solution, print a single integer - 1. Otherwise, your solution should be printed on four lines.
The first line should contain a single integer ka, the size of the corresponding subset of A. The second line should contain ka distinct integers, the indices of the subset of A.
The third line should contain a single integer kb, the size of the corresponding subset of B. The fourth line should contain kb distinct integers, the indices of the subset of B.
Elements in both sets are numbered from 1 to n. If there are multiple possible solutions, print any of them.
Sample Input
10
10 10 10 10 10 10 10 10 10 10
10 9 8 7 6 5 4 3 2 1
Sample Output
1
2
3
5 8 10
Sample Input
5
4 4 3 3 3
2 2 2 2 5
Sample Output
2
2 3
2
3 5
【分析】
题目大意:给出两个有 n n n 个数的集合 A,B,要求在 A 中找一个非空子集,并在 B 中找一个非空子集,使得这两个子集的元素之和相等,输出这两个子集的元素个数以及各个元素在原集合的位置。
我们用 a i a_i ai 表示 A 的前缀和, b i b_i bi 表示 B 的前缀和。
不妨假设 a n < b n a_n<b_n an<bn(即 A 的总和小于 b i b_i bi 表示 B 的总和),如果不满足就交换一下 A 和 B。
由于集合中所有数都在 1 1 1 ~ n n n 之间,所以对于每个 a i a_i ai,总能找到一个最大的 b j b_j bj,使得 0 ≤ a i − b j < n 0\le a_i-b_j<n 0≤ai−bj<n。
算上 a 0 a_0 a0 的话就有 n + 1 n+1 n+1 组这样的 ( a i , b j ) (a_i,b_j) (ai,bj),但是 a i − b j a_i-b_j ai−bj 总共只有 n n n 个取值,根据抽屉原理,一定存在一组 i 1 , i 2 , j 1 , j 2 ( i 1 ≠ i 2 , j 1 ≠ j 2 ) i_1,i_2,j_1,j_2(i_1\ne i_2,j_1\ne j_2) i1,i2,j1,j2(i1=i2,j1=j2),使得:
a i 1 − b j 1 = a i 2 − b j 2 a_{i_1}-b_{j_1}=a_{i_2}-b_{j_2} ai1−bj1=ai2−bj2
移项得到:
a i 1 − a i 2 = b j 1 − b j 2 a_{i_1}-a_{i_2}=b_{j_1}-b_{j_2} ai1−ai2=bj1−bj2
由于 a i , b i a_i,b_i ai,bi 代表的是前缀和,那上式就代表 A 集合在 [ i 2 + 1 i_2+1 i2+1 , , , i 1 i_1 i1 ],B 集合在 [ j 2 + 1 j_2+1 j2+1 , , , j 1 j_1 j1 ] 的和相等。
那么按照上面的方法进行构造就可以解决这道题。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000005
using namespace std;
int n,num1,num2,s1,s2,t1,t2;
int a[N],b[N],A[N],B[N],vis[N],pos[N];
void solve(int *a,int *b)
{
int i,j=0,dis;
memset(vis,-1,sizeof(vis));
for(i=0;i<=n;++i)
{
while(a[i]-b[j]>=n) j++;
pos[i]=j,dis=a[i]-b[j];
if(vis[dis]==-1) vis[dis]=i;
else
{
num1=i-vis[dis],num2=j-pos[vis[dis]];
s1=vis[dis]+1,t1=i,s2=pos[vis[dis]]+1,t2=j;
break;
}
}
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;++i) scanf("%d",&a[i]),A[i]=a[i]+A[i-1];
for(i=1;i<=n;++i) scanf("%d",&b[i]),B[i]=b[i]+B[i-1];
if(A[n]<=B[n]) solve(A,B);
else solve(B,A),swap(num1,num2),swap(s1,s2),swap(t1,t2);
printf("%d\n",num1);
for(i=s1;i<=t1;++i)
printf("%d ",i);
printf("\n%d\n",num2);
for(i=s2;i<=t2;++i)
printf("%d ",i);
return 0;
}