传送门


首先,选取子集的限制太宽了,子集似乎只能枚举,不是很好做。考虑加强限制条件:将“选取子集”的限制变为“选取子序列”的限制。在接下来的讨论中我们将会知道:将限制控制得更紧,问题也一定会有解。

现在我们需要求\(A,B\)的两个子序列,满足两者的和相等。显然可以前缀和,然后就不会做了qwq

考虑下面的算法:假定\(\sum\limits_{a \in A} a < \sum\limits_{b \in B} b\)(如果相等直接全选),设序列\(A\)前缀和为\(sumA_i\),序列\(B\)前缀和为\(sumB_i\)。

对于\(n+1\)个\(sumA_i\),在\(sumB\)中找到最小的大于等于它的元素\(sumB_j\),那么一定有\(sumB_j - sumA_i \in [0,n)\),可能的\(sumB - sumA\)有\(n\)种,但是有\(n+1\)组\(i,j\)。

根据抽屉原理,一定会存在两组\((i_1,j_1)(i_2,j_2)(i_1 > i_2)\)满足\(sumB_{j_1} - sumA_{i_1} = sumB_{j_2} - sumA_{i_2}\),即\(sumB_{j_1} - sumB_{j_2} = sumA_{i_1} - sumA_{i_2}\)。这样我们就找到了一组可行解:在\(A\)中选择\(A_x , x \in (i_2 , i_1]\),在\(B\)中选择\(B_y , y \in (j_2 , j_1]\)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<cmath>
#include<random>
//This code is written by Itst
using namespace std; inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
} #define PII pair < int , int >
#define st first
#define nd second
#define ll long long
const int MAXN = 1e6 + 7;
ll A[MAXN] , B[MAXN];
PII pos[MAXN]; signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
int N = read();
for(int i = 1 ; i <= N ; ++i)
A[i] = A[i - 1] + read();
for(int i = 1 ; i <= N ; ++i)
B[i] = B[i - 1] + read();
bool f = A[N] > B[N];
if(f) swap(A , B);
fill(pos , pos + N + 1 , PII(-1 , -1));
int p = 0;
for(int i = 0 ; i <= N ; ++i){
while(B[p] < A[i]) ++p;
if(pos[B[p] - A[i]] != PII(-1 , -1)){
PII t = pos[B[p] - A[i]];
if(!f){
printf("%d\n" , i - t.first);
for(int j = t.first + 1 ; j <= i ; ++j)
printf("%d " , j);
printf("\n%d\n" , p - t.second);
for(int j = t.second + 1 ; j <= p ; ++j)
printf("%d " , j);
}
else{
printf("%d\n" , p - t.second);
for(int j = t.second + 1 ; j <= p ; ++j)
printf("%d " , j);
printf("\n%d\n" , i - t.first);
for(int j = t.first + 1 ; j <= i ; ++j)
printf("%d " , j);
}
return 0;
}
else pos[B[p] - A[i]] = PII(i , p);
}
puts("-1");
return 0;
}

CF618F Double Knapsack 构造、抽屉原理的更多相关文章

  1. 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_ ...

  2. 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 ...

  3. Codeforces.618F.Double Knapsack(构造 鸽巢原理)

    题目链接 \(Description\) 给定两个大小为\(n\)的可重集合\(A,B\),集合中的元素都在\([1,n]\)内.你需要从这两个集合中各选一个非空子集,使它们的和相等.输出方案. \( ...

  4. CF618F Double Knapsack

    题意简化 给定两个大小为 n 的集合A,B,要求在每个集合中选出一个子集,使得两个选出来的子集元素和相等 元素范围在 1~n ,n<=1e5 题目连接 题解 考虑前缀和 令A集合的前缀和为SA, ...

  5. 【CF618F】Double Knapsack(构造)

    [CF618F]Double Knapsack(构造) 题面 洛谷 Codeforces 题解 很妙的一道题. 发现找两个数集很不爽,我们强制加强限制,我们来找两个区间,使得他们的区间和相等. 把区间 ...

  6. [codeforces 618 F] Double Knapsack (抽屉原理)

    题目链接:http://codeforces.com/contest/618/problem/F 题目: 题目大意: 有两个大小为 N 的可重集 A, B, 每个元素都在 1 到 N 之间. 分别找出 ...

  7. 51nod 1103 N的倍数(抽屉原理)

    1103 N的倍数 题目来源: Ural 1302 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 一个长度为N的数组A,从A中选出若干个数,使得这些数的和是N的倍 ...

  8. POJ2356 Find a multiple 抽屉原理(鸽巢原理)

    题意:给你N个数,从中取出任意个数的数 使得他们的和 是 N的倍数: 在鸽巢原理的介绍里面,有例题介绍:设a1,a2,a3,……am是正整数的序列,试证明至少存在正数k和l,1<=k<=l ...

  9. 华农oj Problem J: 幻化【贪心/抽屉原理】

    Problem J: 幻化 Time Limit: 2 Sec Memory Limit: 128 MB Submit: 18 Solved: 3 [Submit][Status][Web Board ...

随机推荐

  1. pwnable.tw unexploitable 分析

    这题是和pwnable.kr差不多的一道题,主要区别在于没有给syscall.所以需要自己去找. 只有read和sleep两个函数. 思路一是首先劫持堆栈到bss段,然后调用read函数将sleep的 ...

  2. ES6躬行记(18)——迭代器

    ES6将迭代器和生成器内置到语言中,不仅简化了数据处理和集合操作,还弥补了for.while等普通循环的不足,例如难以遍历无穷集合或自定义的树结构等. 迭代器(Iterator)是一种用于迭代的对象, ...

  3. 痞子衡嵌入式:通用NOR接口标准(CFI-JESD68)及SLC Parallel NOR简介

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是CFI标准及SLC Parallel NOR. NOR Flash是嵌入式世界里最常见的存储器,常常内嵌在微控制器里(Parallel型 ...

  4. Python迭代和解析(4):自定义迭代器

    解析.迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html 本文介绍如何自定义迭代器,涉及到类的运算符重载,包括__getitem_ ...

  5. [.NET] 《Effective C#》快速笔记(二)- .NET 资源托管

    <Effective C#>快速笔记(二)- .NET 资源托管 简介 续 <Effective C#>读书笔记(一)- C# 语言习惯. .NET 中,GC 会帮助我们管理内 ...

  6. [MySQL] timestamp和datetime的区别和大坑

    1.timestamp占用4个字节;datetime占用8个字节2.timestamp范围1970-01-01 00:00:01.000000 到 2038-01-19 03:14:07.999999 ...

  7. FrameSet定义页面宽度并且居中

    frameset定义一个1000px的页面并且居中 <frame src = "about:blank"></frame> : 这个语句的功能是在一个框架里 ...

  8. 忘记时间戳的存在——Yii2超实用的自动更新时间戳的Behavior(改进版)

    本文改进了Yii2中内置行为类TimestampBehavior,使得时间戳字段(如created_at,updated_at) 完全自己更新,方便得让你忘记它们的存在. Yii2的内置行为类Time ...

  9. Python xml 模块

    Python xml 模块 TOC 什么是xml? xml和json的区别 xml现今的应用 xml的解析方式 xml.etree.ElementTree SAX(xml.parsers.expat) ...

  10. JavaScript的工作原理:解析、抽象语法树(AST)+ 提升编译速度5个技巧

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 14 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...