CodeForces - 618F Double Knapsack

本文介绍了一种解决两个多重集合中寻找具有相同和的子集的问题。通过使用前缀和技巧,文章提出了一种高效的算法,能够在O(n)的时间复杂度内找到满足条件的子集,并附上了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Discription

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.

Examples

Input
10
10 10 10 10 10 10 10 10 10 10
10 9 8 7 6 5 4 3 2 1
Output
1
2
3
5 8 10
Input
5
4 4 3 3 3
2 2 2 2 5
Output
2
2 3
2
3 5


一道神构造。
设sa[]为a[]的前缀和,sb[]为b的前缀和,对于每个0<=i<=n,我们找到一个最大的使得sb[j]<=sa[i]的j,这样每个sa[i]-sb[j]都是[0,n-1]的整数了(因为如果sa[i]-sb[j]>=n的话,j可以继续后移(a[],b[]中元素都<=n))
所以至少会有一对 i和i'满足 sa[i]-sb[j] == sa[i']-sb[j'],直接输出就行了。。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1000005;
ll a[maxn],b[maxn];
int px[maxn],py[maxn],n;
inline int read(){
	int x=0; char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x;
}
void W(int x){ if(x>=10) W(x/10); putchar(x%10+'0');}
int main(){
	n=read();
	for(int i=1;i<=n;i++) a[i]=read(),a[i]+=a[i-1];
	for(int i=1;i<=n;i++) b[i]=read(),b[i]+=b[i-1];
	for(int i=0,j=0,D;i<=n;i++){
		for(;j<n&&b[j+1]<=a[i];j++);
		D=a[i]-b[j];
		if(px[D]){
			W(i-px[D]+1),puts("");
			for(int o=px[D];o<=i;o++) W(o),putchar(' ');
			puts(""),W(j-py[D]+1),puts("");
			for(int o=py[D];o<=j;o++) W(o),putchar(' ');
			return 0;
		}
		px[D]=i+1,py[D]=j+1;
	}
	return 0;
}

  

 

转载于:https://www.cnblogs.com/JYYHH/p/8927301.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值