T3 「2017 山东一轮集训 Day2」Pair
「2017 山东一轮集训 Day2」Pair
题目描述
给出一个长度为
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 。
输入格式
第一行三个数字
n
,
m
,
h
n,m,h
n,m,h 。
第二行有
m
m
m 个数字
b
1
,
b
2
,
.
.
.
,
b
m
b_1,b_2,...,b_m
b1,b2,...,bm 。
第三行有
n
n
n 个数字
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an 。
输出格式
输出一个数字,
{
a
i
}
\{a_i\}
{ai} 有多少个长度为
m
m
m 的连续子数列能与
{
b
i
}
\{b_i\}
{bi} 匹配。
样例
样例输入 1
5 2 10
5 3
1 8 5 5 7
样例输出 1
2
样例输入 2
2 2 6
2 3
3 4
样例输出 2
1
样例输入 3
4 2 10
5 5
9 3 8 9
样例输出 3
1
数据范围与提示
对于
100
%
100\%
100% 的数据,
1
≤
m
≤
n
≤
150000
1\le m\le n\le 150000
1≤m≤n≤150000,
1
≤
a
i
,
b
i
,
h
≤
1
0
9
1\le a_i,b_i,h\le 10^9
1≤ai,bi,h≤109
思路:
转化题意,使
b
b
b数组的每一位变为
h
−
b
i
h-b_i
h−bi
此时
a
i
a_i
ai与
b
i
b_i
bi能配对即为
a
i
a_i
ai大于
b
i
b_i
bi
令变化后的
b
b
b数组升序排序为
b
1
,
b
2
,
.
.
.
,
b
m
b_1,b_2,...,b_m
b1,b2,...,bm
统计
a
a
a子串中大于
b
i
b_i
bi的个数,记为
s
i
s_i
si,得到
s
s
s数组
匹配时贪心,将最小的
a
i
a_i
ai与最小的
b
i
b_i
bi匹配
则
a
a
a与
b
b
b能配对当且仅当对于每一位
s
i
≤
i
s_i\le i
si≤i,即
s
i
−
i
≤
0
s_i-i\le 0
si−i≤0
可以用线段树维护
O
(
n
)
O(n)
O(n)枚举子串,每一次移动都删除一个数,添加一个数
发现每一次添加或删除都影响一段前缀,区间修改即可
上传统计答案维护最小值,当整个区间的最小值都大于等于零时,就匹配上了
数据只需要离散
b
b
b,在
b
b
b中找到小于等于
a
i
a_i
ai的最大数,
a
i
a_i
ai对其前缀产生贡献
注意:
l
o
w
e
r
_
b
o
u
n
d
lower\_bound
lower_bound是返回大于等于
i
i
i的最小数的位置
u
p
p
e
r
_
b
o
u
n
d
upper\_bound
upper_bound是返回大于
i
i
i的最小数的位置
在
b
b
b中找
a
a
a时要找小于等于
a
i
a_i
ai的最大数,应该用
u
p
p
e
r
_
b
o
u
n
d
upper\_bound
upper_bound后再减一
代码:
(这里时将
b
b
b降序排序,维护后缀)
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register
#define lch p<<1
#define rch p<<1|1
inline char ch(){
static char buf[1<<21],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int in{
int s=0,f=1;char x;
for(x=ch();x<'0'||x>'9';x=ch()) if(x=='-') f=-1;
for( ;x>='0'&&x<='9';x=ch()) s=(s<<1)+(s<<3)+(x&15);
return f==1?s:-s;
}
const int A=5e5+5;
int n,m,all;
int a[A],b[A],c[A],len;
int sum[A];
struct Tree{
int l,r,min,tag;
}tree[4*A];
int ans=0;
inline void lsh(){
sort(c+1,c+1+m);
len=unique(c+1,c+1+m)-(c+1);
for(re int i=1;i<=m;++i){
b[i]=lower_bound(c+1,c+1+m,b[i])-c;
sum[b[i]]++;
}
for(int i=len+1;i>0;i--)//这里len不加1会玄学出错
sum[i]=sum[i+1]+sum[i];
return;
}
inline void pushup(int p){
tree[p].min=min(tree[lch].min,tree[rch].min);
return;
}
inline void pushdown(int p){
tree[lch].min+=tree[p].tag;
tree[rch].min+=tree[p].tag;
tree[lch].tag+=tree[p].tag;
tree[rch].tag+=tree[p].tag;
tree[p].tag=0;
return;
}
inline void build(int p,int l,int r){
tree[p].l=l,tree[p].r=r;
if(l==r){
tree[p].min=-sum[l];
return;
}
int mid=(l+r)>>1;
build(lch,l,mid),build(rch,mid+1,r);
pushup(p);
return;
}
inline void add(int p,int l,int r,int val){
if(tree[p].l>=l&&tree[p].r<=r){
tree[p].min+=val;
tree[p].tag+=val;
return;
}
pushdown(p);
int mid=(tree[p].l+tree[p].r)>>1;
if(l<=mid) add(lch,l,r,val);
if(r>=mid+1) add(rch,l,r,val);
pushup(p);
return;
}
signed main(){
// freopen("pair.in","r",stdin);
// freopen("pair.out","w",stdout);
n=in,m=in,all=in;
for(re int i=1;i<=m;++i){
b[i]=in;
b[i]=c[i]=all-b[i];
}
lsh();
for(re int i=1;i<=n;++i){
a[i]=in;
if(a[i]<c[1]){
a[i]=0;
continue;
}
if(a[i]>c[len]){
a[i]=len;
continue;
}
if(a[i]>=c[1]&&a[i]<=c[len]){
a[i]=upper_bound(c+1,c+1+len,a[i])-(c+1);
continue;
}
}
build(1,1,len);
for(re int i=1;i<m;++i)
if(a[i]!=0) add(1,1,a[i],1);
for(re int i=m;i<=n;++i){
if(a[i-m]!=0) add(1,1,a[i-m],-1);
if(a[i]!=0) add(1,1,a[i],1);
if(tree[1].min>=0) ans++;
}
printf("%d\n",ans);
return 0;
}