CF618F Double Knapsack

Double Knapsack

CF618F (Luogu)

题面翻译

给你两个可重集 \(A, B\)\(A, B\) 的元素个数都为 \(n\),它们中每个元素的大小 \(x\in [1,n]\)。请你分别找出 \(A, B\) 的子集,使得它们中的元素之和相等。

\(n\leq 10^6\)

题目描述

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.

输入格式

The first line of the input contains a single integer $ n $ ( $ 1<=n<=1000000 $ ) — 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.

输出格式

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 $ k_{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 $ .

The third line should contain a single integer $ k_{b} $ , the size of the corresponding subset of $ B $ . The fourth line should contain $ 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

样例输入 #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

样例输入 #2

5
4 4 3 3 3
2 2 2 2 5

样例输出 #2

2
2 3
2
3 5

Solution

一道思维题,需要有比较强的想象力才可能想到正解。

我们先假设这个问题一定存在一组符合题意的解,而且这组解在两个序列中还是连续的。定义 \(a\) 数组的前缀和为 \(suma\)\(b\) 数组的前缀和为 \(sumb\)。定义 \(c_i\) 为最靠右的下标并且满足 \(suma_i \ge sumb_{c_i}\)。根据定义有:

\[suma_i< sumb_{c_i+1} \]

\[suma_i< sumb_{c_i} +b_{c_i+1} \]

移项得:

\[suma_i-sumb_{c_i}<b_{c_i+1} \]

因为 \(b_{c_i+1}\) 的值域是 \([1,n]\) 的,因此 \(0\le suma_i-sumb_{c_i}<n\),总共有 \(n\) 个可能的取值,而 \(i\) 的值域是 \([0,n]\) 的,也就是说有 \(n+1\) 种可能的情况,那么根据抽屉原理,一定会存在有一组满足:

\[suma_i-sumb_{c_i}=suma_j-sumb_{c_j} \]

移项得:

\[suma_i-suma_j=sumb_{c_i}-sumb_{c_j} \]

这不就裸的前缀和式子?因此可以证明一定存在答案,并且答案一定是在两个序列中连续的一段子序列。

考虑如何求出 \(c\)。不难发现,因为 \(suma\) 是递增的,因此 \(c\) 也一定是单调不降的,所以用一个指针来计算 \(c\) 即可,同时计算此时的 \(suma_i-sumb_{c_i}\),如果这一个值之前出现过,那么就是找到了一组可行的答案,否则标记这个值,继续往后找。

Code

需要注意因为序列中的数字值域是 \([1,1\times 10^6]\) 的,并且有 \(1\times 10^6\) 个数,所以前缀和最大可以到 \(1\times 10^{12}\),所以记得开 long long

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
//#define int long long
using namespace std;
template<typename T> void read(T &k)
{
	k=0;T flag=1;char b=getchar();
	while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
	while (isdigit(b)) {k=k*10+b-48;b=getchar();}
	k*=flag;
}
template<typename T> void write(T k) {if (k<0) {putchar('-'),write(-k);return;}if (k>9) write(k/10);putchar(k%10+48);}
template<typename T> void writewith(T k,char c) {write(k);putchar(c);}
const int _SIZE=1e6;
int n,a[_SIZE+5],b[_SIZE+5];
long long suma[_SIZE+5],sumb[_SIZE+5],id[_SIZE+5][2];
bool flag[_SIZE+5];
signed main()
{
	read(n);
	for (int i=1;i<=n;i++) read(a[i]),suma[i]=suma[i-1]+a[i];
	for (int i=1;i<=n;i++) read(b[i]),sumb[i]=sumb[i-1]+b[i];
	bool swaped=0;
	if (suma[n]>sumb[n]) swaped=1,swap(suma,sumb);
	int j=0,al,ar,bl,br;
	for (int i=0;i<=n;i++)
	{
		while (suma[i]>=sumb[j] && j<=n) j++;j--;
		if (flag[suma[i]-sumb[j]])
		{
			al=id[suma[i]-sumb[j]][0]+1;ar=i;
			bl=id[suma[i]-sumb[j]][1]+1;br=j;
			break;
		}
		flag[suma[i]-sumb[j]]=1;
		id[suma[i]-sumb[j]][0]=i;
		id[suma[i]-sumb[j]][1]=j;
	}
	if (swaped) swap(al,bl),swap(ar,br);
	writewith(ar-al+1,'\n');
	for (int i=al;i<=ar;i++) writewith(i,' ');puts("");
	writewith(br-bl+1,'\n');
	for (int i=bl;i<=br;i++) writewith(i,' ');puts("");
	return 0;
}

posted @ 2022-08-19 10:52  Hanx16Msgr  阅读(56)  评论(0)    收藏  举报