[codeforces 618 F] Double Knapsack (抽屉原理)
题目链接:http://codeforces.com/contest/618/problem/F
题目:
题目大意:
有两个大小为 N 的可重集 A, B, 每个元素都在 1 到 N 之间. 分别找出 A 和 B 的一个子集, 使得这两个子集元素之和相等.
分别输出集合A和集合B的子集的个数以及子集中元素在原集合中的位置
N ≤ $10^6$
题解:
首先我们证明一个结论,存在一组方案,满足两个子集在A中和在B中都是连续的一段
把两个集合看成两个数组,分别计算出前缀和sa,sb
对于每个i(0<=i<=n),我们j为满足0<=sa[i]-sb[j]<=n-1的最大的j,设d[i]=sa[i]-sb[j],可以发现j的单调递增的
我们发现d数组一共有n+1个元素(包括i=0,sa[i]=0的情况),并且我们又发现d[i]的取值只有n个。那么根据抽屉原理,至少有两个d数组中的元素是相等的
于是我们有sa[i']-sb[j']=sa[i]-sb[j](i'>i)
移项之后得到sa[i']-sa[i]=sb[j']-sb[j]
这个时候我们就知道在A数组中i+1~i'这一段元素之和与B数组中j+1~j'这一段元素之和相等
证毕
其实上面的证明过程就是我们本题的做法,我们用two pointers处理出d数组,然后判断当前的d值在之前是否出现过,这个时候我们就得到了答案
值得注意的是,我们需要sa[n]<=sb[n],因为若是sa[n]>sb[n]可能出现对于i=n找不到一个j满足上述条件
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std; const int N=1e6+;
int n,cnt1,cnt2,st1,st2,ed1,ed2;
int sa[N],sb[N],vis[N],p[N];
inline int read()
{
char ch=getchar();
int s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
void solve(int a[],int b[])
{
memset(vis,-,sizeof(vis));
int j=;
for (int i=;i<=n;i++)
{
while (a[i]-b[j]>=n) j++;
int d=a[i]-b[j];
if (vis[d]!=-)
{
cnt1=i-vis[d];
st1=vis[d]+;ed1=i;
cnt2=j-p[vis[d]];
st2=p[vis[d]]+;ed2=j;
break;
}
vis[d]=i;p[i]=j;
}
}
int main()
{
n=read();
for (int i=;i<=n;i++) sa[i]=sa[i-]+read();
for (int i=;i<=n;i++) sb[i]=sb[i-]+read();
if (sa[n]<=sb[n])
{
solve(sa,sb);
}
else
{
solve(sb,sa);swap(cnt1,cnt2);swap(st1,st2);swap(ed1,ed2);
}
printf("%d\n",cnt1);
for (int i=st1;i<=ed1;i++) printf("%d ",i);
printf("\n");
printf("%d\n",cnt2);
for (int i=st2;i<=ed2;i++) printf("%d ",i);
printf("\n");
return ;
}
[codeforces 618 F] Double Knapsack (抽屉原理)的更多相关文章
- Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) F. Double Knapsack 鸽巢原理 构造
F. Double Knapsack 题目连接: http://www.codeforces.com/contest/618/problem/F Description You are given t ...
- CF618F Double Knapsack 构造、抽屉原理
传送门 首先,选取子集的限制太宽了,子集似乎只能枚举,不是很好做.考虑加强限制条件:将"选取子集"的限制变为"选取子序列"的限制.在接下来的讨论中我们将会知道: ...
- 2018.09.27 codeforces618F. Double Knapsack(抽屉原理+构造)
传送门 思维题. 考虑维护两个数列的前缀和a1,a2,a3,...,ana_1,a_2,a_3,...,a_na1,a2,a3,...,an和b1,b2,b3,...,bnb_1,b_2,b_ ...
- CodeForces 485A Factory (抽屉原理)
A. Factory time limit per test 1 second memory limit per test 256 megabytes input standard input out ...
- Codeforces Round #319 (Div. 2) B. Modulo Sum 抽屉原理+01背包
B. Modulo Sum time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- Codeforces 958C3 - Encryption (hard) 区间dp+抽屉原理
转自:http://www.cnblogs.com/widsom/p/8863005.html 题目大意: 比起Encryption 中级版,把n的范围扩大到 500000,k,p范围都在100以内, ...
- 51nod 1103 N的倍数(抽屉原理)
1103 N的倍数 题目来源: Ural 1302 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 一个长度为N的数组A,从A中选出若干个数,使得这些数的和是N的倍 ...
- 【CF618F】Double Knapsack(构造)
[CF618F]Double Knapsack(构造) 题面 洛谷 Codeforces 题解 很妙的一道题. 发现找两个数集很不爽,我们强制加强限制,我们来找两个区间,使得他们的区间和相等. 把区间 ...
- bzoj#4722-由乃【倍增,抽屉原理,bitset】
正题 题目链接:https://darkbzoj.tk/problem/4722 题目大意 给出一个长度为\(n\)的序列值域为\([0,v)\),要求支持操作 询问一个区间能否找到两个没有交的非空下 ...
随机推荐
- mycat的配置和学习
1.mycat一共三个配置文件. 1)server.xml:配置逻辑库的名称访问的账号密码 <user name="root"> <property name=& ...
- ZOJ 2705
这题,找找规律,可以发现一个斐波那契数列.按照斐波那契数列求和,知道, SUM=Fn+2-F1,于是,该长度为Fn+2的倍数.因为斐波那契数列不一定是从1开始的,而从2开始的每个数都是从1开始的倍数. ...
- Android Touch事件传递机制全面解析(从WMS到View树)
转眼间近一年没更新博客了,工作一忙起来.非常难有时间来写博客了,因为如今也在从事Android开发相关的工作,因此以后的博文也会很多其它地专注于这一块. 这篇文章准备从源代码层面为大家带来Touch事 ...
- linux定时备份mysql数据库文件
1.设定定时器:终端敲入:crontab -e命令 2,然后写入 00 23 * * * /home/db_bak_file/dbbak.sh >>/home/db_bak_fil ...
- 51nod-1359: 循环探求
[传送门:51nod-1359] 简要题意: 给出n和k,求出最小的x满足$n^{x}≡n(mod\;10^{k})$ 题解: 真是一道有(du)趣(liu)题目 首先我们设X[k-1]为$n^{x} ...
- Oracle RAC 实施
第 1 步 — 确定项目范围 理由 我们实施 Oracle RAC 是为了使我们的应用程序可伸缩和高度可用,以及为我们的客户提供更可靠的服务. 目标/可交付产品 该项目的最终产品将是一个新的 Orac ...
- VC++基于CXImage库实现缩略图
一般的图像处理软件都对读入程序的图像文件建一个缩略图的列表,像ACDSee那样.笔者最近在做一个图像处理的项目,处理的原始数据就是图像文件.从项目一开始就想做一个缩略图,但一直苦于技术水平有限,且时间 ...
- HD-ACM算法专攻系列(9)——大菲波数
题目描述: 源码: 运用Java大数求解. import java.math.BigInteger; import java.util.*; public class Main { //主函数 pub ...
- 51nod 1101 换零钱 完全背包的变型 动态规划
题目: 思路: ;i < ; i++){ for(int j = a[i];j <= n; j++){ dp[j] = (dp[j] + dp[j-a[i]])%mod; } } a[i] ...
- Date日期类 Calendar日历类 完成可视化日历
package com.test; import java.text.DateFormat; import java.text.ParseException; import java.text.Sim ...