卧薪尝胆,厚积薄发。
Double Knapsack
Date: Wed Oct 10 16:48:26 CST 2018 In Category: NoCategory

Description:

给两个集合,每个数都在 $1\sim n$ 范围内,求两个子集使得权值和相等。
$1\leqslant n\leqslant 10^6$

Solution:

构造题,肯定是利用鸽笼原理,假设 $Sa_n\leqslant Sb_n$ ,那么对于每个 $i$ 找到第一个 $Sa_i\leqslant Sb_j$ 的位置,那么 $Sb_j-Sa_i\in[0,n-1]$ ,有 $n$ 种取值,这样的前缀有 $n+1$ 个(算上 $i=0$ ),那么一定能找到 $Sb_{j_1}-Sa_{i_1}=Sb_{j_2}-Sa_{i_2}$ ,那么之间的部分就是答案。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n;
#define MAXN 1000010
int a[MAXN],b[MAXN];
long long sa[MAXN],sb[MAXN];
int p[MAXN];
int ans[2][2];
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)
{
scanf("%d",&a[i]);
sa[i] = sa[i - 1] + a[i];
}
for(int i = 1;i <= n;++i)
{
scanf("%d",&b[i]);
sb[i] = sb[i - 1] + b[i];
}
bool tag = false;
if(sa[n] > sb[n])
{
tag = true;
swap(a,b);
swap(sa,sb);
}
memset(p,-1,sizeof(p));
for(int i = 0;i <= n;++i)
{
int pb = lower_bound(sb,sb + 1 + n,sa[i]) - sb;
if(p[sb[pb] - sa[i]] != -1)
{
ans[0][0] = p[sb[pb] - sa[i]];ans[0][1] = i;
ans[1][0] = lower_bound(sb,sb + 1 + n,sa[ans[0][0]]) - sb;
ans[1][1] = pb;
break;
}
p[sb[pb] - sa[i]] = i;
}
if(tag)
{
swap(ans[0][0],ans[1][0]);swap(ans[0][1],ans[1][1]);
swap(a,b);
}
cout << ans[0][1] - ans[0][0] << endl;
for(int i = ans[0][0] + 1;i <= ans[0][1];++i)cout << i << " ";cout << endl;
cout << ans[1][1] - ans[1][0] << endl;
for(int i = ans[1][0] + 1;i <= ans[1][1];++i)cout << i << " ";cout << endl;
return 0;
}
In tag: 算法-构造
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡