卧薪尝胆,厚积薄发。
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
ღゝ◡╹)ノ♡