传送门


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

现在我们需要求\(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. REST API设计指导——译自Microsoft REST API Guidelines(四)

    前言 前面我们说了,如果API的设计更规范更合理,在很大程度上能够提高联调的效率,降低沟通成本.那么什么是好的API设计?这里我们不得不提到REST API. 关于REST API的书籍很多,但是完整 ...

  2. MVC Scaffolding SmartCode-Engine 更新

    概述 通过扩展visual studio.net scaffolding组件,添加了一套功能完善的代码模板,包括Controller,Model,View,Businessd等各种功能的代码,配合En ...

  3. Java——代码复用(组合和继承)

    前言 "复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它必须还能够做更多的事情." Java解决问题都围绕类展开的, ...

  4. mac终端调用编辑器打开文件

    1.调用atom编辑器,前提是编辑器打开, cd+filename 2 .VScode里面: 调用终端:ctrl + `(esc健下面那个) 安装:shift + command+ p 安装如下插件 ...

  5. C#程序员知识体系

    [https://blog.csdn.net/zj735539703/article/details/50409476] 基础部分 C# 基础语法 OOP的概念,面向对象的理解 继承 封装 多态 AS ...

  6. vb.net 分割byte数组的方法SplitBytes

    以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As Li ...

  7. 微信小程序组件minui在mac系统的使用注意事项

    1.mac系统使用npm 安装组件的时候,一定要注意mac系统的终端一定要用root用户操作. 具体的命令如下:sudo -i,然后提示输入系统的密码就进入了root操作用户. 2.然后就根据minu ...

  8. 设置抓包工具Fiddler的host

    大家都知道在电脑本地上有一个Host文件. Hosts文件主要作用是定义IP地址和主机名的映射关系,是一个映射IP地址和主机名的规定.可以用文本文件打开!当用户在浏览器中输入一个需要登录的网址时,系统 ...

  9. Vue组件的is具体用法

    1.为什么要使用is 在vue的官网组件部分中,有明确的描述:当使用 DOM 作为模板时 (例如,使用 el 选项来把 Vue 实例挂载到一个已有内容的元素上),你会受到 HTML 本身的一些限制,因 ...

  10. Android 屏幕适配插件 ScreenMatch

    概述 ScreenMatch是根据你的需要,生成需要适配的尺寸的文件,手机会根据屏幕相关参数自动寻找合适的尺寸文件 添加插件 如图,打开Android Studio的Settings设置,找到Plug ...