LOJ6062「2017 山东一轮集训 Day2」Pair(Hall定理,线段树)
题面
给出一个长度为
n
n
n 的数列
{
a
i
}
\{a_i\}
{ai} 和一个长度为
m
m
m 的数列
{
b
i
}
\{b_i\}
{bi},求
{
a
i
}
\{a_i\}
{ai} 有多少个长度为
m
m
m 的连续子数列能与
{
b
i
}
\{b_i\}
{bi} 匹配。
两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当且仅当它们的和不小于
h
h
h。
1
≤
m
≤
n
≤
150000.
1\leq m\leq n\leq 150000.
1≤m≤n≤150000.
题解
条件等价于子二分图存在完备匹配。
我们从数列
B
B
B 的角度考虑,根据 Hall 定理,要保证
B
B
B 的任意子集
S
S
S 满足
∣
S
∣
≤
∣
N
(
S
)
∣
|S|\leq |N(S)|
∣S∣≤∣N(S)∣ ,
N
(
S
)
N(S)
N(S) 表示
S
S
S 中所有点的邻接点构成的集合。
然后,我们会发现连边具有单调性,
a
i
a_i
ai 可以和所有大于等于
h
−
a
i
h-a_i
h−ai 的
b
j
b_j
bj 连边。所以,我们把
B
B
B 从小到大排序,每个
a
i
a_i
ai 的邻接点集就是
B
B
B 的某段后缀。
这就意味着,对于
∀
i
<
j
≤
m
,
N
(
i
)
⊆
N
(
j
)
\forall i<j\leq m~,~N(i)\sube N(j)
∀i<j≤m , N(i)⊆N(j) ,即
i
i
i 的邻接点集一定是
j
j
j 的邻接点集的子集。很容易就能得到,如果
B
B
B 的某前缀
P
P
P 满足
∣
P
∣
≤
∣
N
(
P
)
∣
|P|\leq|N(P)|
∣P∣≤∣N(P)∣ ,那么对于任意
S
⊆
B
,
∣
S
∣
=
∣
P
∣
S\sube B,|S|=|P|
S⊆B,∣S∣=∣P∣ ,也一定满足
∣
S
∣
≤
∣
N
(
S
)
∣
|S|\leq|N(S)|
∣S∣≤∣N(S)∣ 。
于是,我们需要考虑的子集从
2
m
−
1
2^m-1
2m−1 个锐减至
m
m
m 个。而且,明显可以用线段树维护每个前缀的邻接点集大小,存在完备匹配的条件即
min
{
∣
N
(
P
)
∣
−
∣
P
∣
}
≥
0
\min\{|N(P)|-|P|\}\geq 0
min{∣N(P)∣−∣P∣}≥0 。
时间复杂度
O
(
n
log
m
)
O(n\log m)
O(nlogm) 。
CODE
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 150005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
LL read() {
LL f=1,x=0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s=getchar();}
while(s >= '0' && s <= '9') {x = (x<<3) + (x<<1) + (s^48);s = getchar();}
return f * x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);};
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
int n,m,s,o,k;
int H;
int a[MAXN],b[MAXN],ad[MAXN];
int tre[MAXN<<2],lz[MAXN<<2],M;
void maketree(int n) {
M=1;while(M<n+2)M<<=1;
for(int i = 1;i <= n;i ++) {
tre[M+i] = -i;
}
for(int i = M-1;i > 0;i --) {
tre[i] = min(tre[i<<1],tre[i<<1|1]);
}return ;
}
void addtree(int l,int r,int y) {
if(l > r) return ;
for(int s=M+l-1,t=M+r+1;s || t;s >>= 1,t >>= 1) {
if(s<M) tre[s] = min(tre[s<<1],tre[s<<1|1]) + lz[s];
if(t<M) tre[t] = min(tre[t<<1],tre[t<<1|1]) + lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s&1)) tre[s^1] += y,lz[s^1] += y;
if(t & 1) tre[t^1] += y,lz[t^1] += y;
}
}return ;
}
int main() {
n = read();m = read();H = read();
for(int i = 1;i <= m;i ++) {
b[i] = read();
}
for(int i = 1;i <= n;i ++) {
a[i] = read();
}
sort(b + 1,b + 1 + m);
maketree(m);
int ans = 0;
for(int i = 1;i <= n;i ++) {
ad[i] = lower_bound(b + 1,b + 1 + m,H-a[i]) - b;
addtree(ad[i],m,1);
if(i > m) addtree(ad[i-m],m,-1);
if(tre[1] >= 0) ans ++;
}
AIput(ans,'\n');
return 0;
}
LOJ6062「2017 山东一轮集训 Day2」Pair(Hall定理,线段树)的更多相关文章
- loj#6062. 「2017 山东一轮集训 Day2」Pair hall定理+线段树
题意:给出一个长度为 n的数列 a和一个长度为 m 的数列 b,求 a有多少个长度为 m的连续子数列能与 b匹配.两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当 ...
- 【LOJ6062】「2017 山东一轮集训 Day2」Pair(线段树套路题)
点此看题面 大致题意: 给出一个长度为\(n\)的数列\(a\)和一个长度为\(m\)的数列\(b\),求\(a\)有多少个长度为\(m\)的子串与\(b\)匹配.数列匹配指存在一种方案使两个数列中的 ...
- LOJ #6062. 「2017 山东一轮集训 Day2」Pair
这是Lowest JN dalao昨天上课讲的一道神题其实是水题啦 题意很简单,我们也很容易建模转化出一个奇怪的东西 首先我们对b进行sort,然后我们就可以通过二分来判断出这个数可以和哪些数配对 然 ...
- ACM-ICPC 2017 西安赛区现场赛 K. LOVER II && LibreOJ#6062. 「2017 山东一轮集训 Day2」Pair(线段树)
题目链接:西安:https://nanti.jisuanke.com/t/20759 (计蒜客的数据应该有误,题目和 LOJ 的大同小异,题解以 LOJ 为准) LOJ:https://l ...
- Loj #6069. 「2017 山东一轮集训 Day4」塔
Loj #6069. 「2017 山东一轮集训 Day4」塔 题目描述 现在有一条 $ [1, l] $ 的数轴,要在上面造 $ n $ 座塔,每座塔的坐标要两两不同,且为整点. 塔有编号,且每座塔都 ...
- Loj #6073.「2017 山东一轮集训 Day5」距离
Loj #6073.「2017 山东一轮集训 Day5」距离 Description 给定一棵 \(n\) 个点的边带权的树,以及一个排列$ p\(,有\)q $个询问,给定点 \(u, v, k\) ...
- Loj 6068. 「2017 山东一轮集训 Day4」棋盘
Loj 6068. 「2017 山东一轮集训 Day4」棋盘 题目描述 给定一个 $ n \times n $ 的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置 $ (x, y),(u, ...
- 「2017 山东一轮集训 Day5」苹果树
「2017 山东一轮集训 Day5」苹果树 \(n\leq 40\) 折半搜索+矩阵树定理. 没有想到折半搜索. 首先我们先枚举\(k\)个好点,我们让它们一定没有用的.要满足这个条件就要使它只能和坏 ...
- 【LOJ#6066】「2017 山东一轮集训 Day3」第二题(哈希,二分)
[LOJ#6066]「2017 山东一轮集训 Day3」第二题(哈希,二分) 题面 LOJ 题解 要哈希是很显然的,那么就考虑哈希什么... 要找一个东西可以表示一棵树,所以我们找到了括号序列. 那么 ...
随机推荐
- java中的final与可变类型、不可变类型的关系
如果你对final和不可变类型的概念与区别有疑问的话,可以打开这篇文章.希望我的解答可以帮到您! 1.不可变类型: 什么是可变类型,什么是不可变类型呢? 首先我们看一下下面的这行代码: String ...
- vue.js中英文api
全局配置 Vue.config is an object containing Vue's global configurations. You can modify its properties l ...
- Linux IO重定向和管道
计算机组成部分: 由io . 控制器.计算器.存储器组成 IO: input output 计算机里面通过终端窗口实现输入和输出,键盘鼠标屏幕这些只是手段,真正完成输入输出的是终端窗口 标准输入.出. ...
- python小题目练习(四)
题目:JAVA和Python实现冒泡排序 实现代码: # Java实现对数组中的数字进行冒泡排序scoreList = [98, 87, 89, 90, 69, 50]temp = 0for i in ...
- 【小程序自动化Minium】二、元素定位-Page接口中的 get_element() 与 get_elements()
UI自动化中的重要工作就是元素定位了,高效精准的定位方法可以让工作事半功倍. 在过去的一段web自动化经历中,使用的selenium库支持了多种定位方法,我们可以利用这些定位方法来做进一步封装,写出符 ...
- SDK导入问题 __imp_与__imp__
目前刚刚实习一周,接触的第一个项目是CMake编译的QT项目,需要引入公司的SDK,编译能过去但是程序就是找不到SDK的接口, 排查了半天发现问题在于:公司的SDK是32位的,自己项目的build k ...
- SpringBoot开发 - 什么是热部署和热加载?devtool的原理是什么?
在SpringBoot开发调试中,如果我每行代码的修改都需要重启启动再调试,可能比较费时间:SpringBoot团队针对此问题提供了spring-boot-devtools(简称devtools)插件 ...
- SpringBoot接口 - 如何优雅的对参数进行校验?
在以SpringBoot开发Restful接口时, 对于接口的查询参数后台也是要进行校验的,同时还需要给出校验的返回信息放到上文我们统一封装的结构中.那么如何优雅的进行参数的统一校验呢? @pdai ...
- DENIED Redis is running in protected mode because protected mode is enabled
DENIED Redis is running in protected mode because protected mode is enabled redisson连接错误 Unable to i ...
- 【有用的SQL】查Greenplum的数据字典
Greenplum 查询哪个表的分布键 ( Greenplum ) SELECT att.nspname AS 模式名 , att.relname AS 表名 , table_comment AS 表 ...