原题链接:http://codeforces.com/problemset/problem/618/F
Double Knapsack
题目描述
You are given two multisets A A and B B . Each multiset has exactly n n integers each between 1 1 and n n inclusive. Multisets may contain multiple copies of the same number.
You would like to find a nonempty subset of A A and a nonempty subset of B 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 −1 . Otherwise, print the indices of elements in any such subsets of A A and B B that have the same sum.
输入输出格式
输入格式:
The first line of the input contains a single integer n (1<=n<=1000000 ) — the size of both multisets.
The second line contains n n integers, denoting the elements of A . Each element will be between 1 1 and n n inclusive.
The third line contains n n integers, denoting the elements of B . Each element will be between 1 and n inclusive.
输出格式:
If there is no solution, print a single integer -1 −1 . Otherwise, your solution should be printed on four lines.
The first line should contain a single integer ka k a a the size of the corresponding subset of A . The second line should contain k_{a} distinct integers, the indices of the subset of A A .
The third line should contain a single integer kb k b , the size of the corresponding subset of B B . The fourth line should contain kb k b 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.
输入输出样例
输入样例#1:
10
10 10 10 10 10 10 10 10 10 10
10 9 8 7 6 5 4 3 2 1
输出样例#1:
1
2
3
5 8 10
输入样例#2:
5
4 4 3 3 3
2 2 2 2 5
输出样例#2:
2
2 3
2
3 5
题目大意
给你两个可重集 A,B ,A、B的元素个数都为n且n⩽1000000,它们中每个元素的大小x∈[1,n]。请你分别找出A ,B的可重子集,使得它们中的元素之和相等。
输入格式:
第一行为一个整数n, 表示两个子集的大小。
第二、三行皆为n个整数,分别表示AA 、BB 的元素。
输出格式:
如果无解, 请输出-1。如果有解, 第一行输出A 的可重子集中元素的个数,第二行输出该子集中元素在A 中对应的下标;第三行输出B 的可重子集中元素的个数, 第四行输出该子集中元素在B 中对应的下标。
数据可能存在多组解, 输出一组即可。
题解
我们对于两个数列分别求前缀和,设两个前缀和分别为 f(a)=∑ai=1Ai,g(b)=∑bi=1Bi f ( a ) = ∑ i = 1 a A i , g ( b ) = ∑ i = 1 b B i ,假设 f(n)<g(n) f ( n ) < g ( n ) ,即 A A 数列中的值小于数列。找一个最小的 g(b) g ( b ) 使得 g(b)⩾f(a) g ( b ) ⩾ f ( a ) ,那么肯定有 g(b)−f(a)∈[0,n−1] g ( b ) − f ( a ) ∈ [ 0 , n − 1 ] ,则共有 n n 种取值,而因为我们从0开始求解,会求出个取值,所以肯定会有两个重复的取值,那么这两个前缀之间的串的和肯定是一样的。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1e6+5;
struct sd{
int cot,t1,t2;
};
int n;
ll x1[M],x2[M];
sd bak[M];
void in()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&x1[i]),x1[i]+=x1[i-1];
for(int i=1;i<=n;++i)
scanf("%lld",&x2[i]),x2[i]+=x2[i-1];
}
void ac()
{
bool flag=0;
if(x1[n]>x2[n])flag=1,swap(x1,x2);
int j=0,hh,s1=1,s2=1,e1=1,e2=1;
for(int i=0;i<=n;++i)
{
while(x2[j]<x1[i])++j;
hh=x2[j]-x1[i];
bak[hh].cot++;
if(bak[hh].cot>=2)
{
s1=bak[hh].t1;
s2=bak[hh].t2;
e1=i;e2=j;
break;
}
bak[hh].t1=i;bak[hh].t2=j;
}
if(flag)
swap(x1,x2),swap(e1,e2),swap(s1,s2);
printf("%d\n",e1-s1);
for(int i=s1+1;i<=e1;++i)
printf("%d ",i);
printf("\n%d\n",e2-s2);
for(int i=s2+1;i<=e2;++i)
printf("%d ",i);
}
int main()
{
in();ac();
return 0;
}