题目描述
给出一个长度为 的数列 和一个长度为 的数列 ,求 有多少个长度为 的连续子数列能与 匹配。
两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当且仅当它们的和不小于 。
输入格式
第一行三个数字 。
第二行有 个数字 。
第三行有 个数字 。
输出格式
输出一个数字, 有多少个长度为 的连续子数列能与 匹配。
样例
样例输入 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
数据范围与提示
对于 的数据,;
对于 的数据,;
对于 的数据,;
对于 的数据,。
SOLUTION:
用霍尔定理可以推出一个式子
对a的一个区间
用sum i 表示a中连接b i的点的个数
若对于每一个sum i 满足 sum i>=i 则可以完美匹配
CODE:
#include <bits/stdc++.h>
#define REP(i, a, b) for (int i = a; i <= b; ++i)
typedef long long ll;
using namespace std;
void File() {
freopen("loj6062.in", "r", stdin);
freopen("loj6062.out", "w", stdout);
}
const int maxn = 1.5e5 + 10;
int n, m, h, a[maxn], b[maxn], ans;
struct Segment_Tree {
#define mid ((l + r) >> 1)
#define lc rt << 1
#define rc rt << 1 | 1
#define lson lc, l, mid
#define rson rc, mid + 1, r
int Min[maxn << 2], tag[maxn << 2];
void pushdown(int rt) {
Min[lc] += tag[rt];
tag[lc] += tag[rt];
Min[rc] += tag[rt];
tag[rc] += tag[rt];
tag[rt] = 0;
}
void build(int rt, int l, int r) {
if (l == r)
Min[rt] = -l;
else {
build(lson);
build(rson);
Min[rt] = min(Min[lc], Min[rc]);
}
}
void modify(int rt, int l, int r, int L, int R, int x) {
if (L > R)
return;
if (L <= l && r <= R) {
Min[rt] += x;
tag[rt] += x;
} else {
if (tag[rt])
pushdown(rt);
if (L <= mid)
modify(lson, L, R, x);
if (R >= mid + 1)
modify(rson, L, R, x);
Min[rt] = min(Min[lc], Min[rc]);
}
}
} T;
void init() {
scanf("%d%d%d", &n, &m, &h);
REP(i, 1, m) scanf("%d", &b[i]);
sort(b + 1, b + m + 1);
REP(i, 1, n) {
scanf("%d", &a[i]);
a[i] = lower_bound(b + 1, b + m + 1, h - a[i]) - b;
}
T.build(1, 1, m);
REP(i, 1, m - 1) T.modify(1, 1, m, a[i], m, 1);
}
int main() {
// File();
init();
REP(i, m, n) {
T.modify(1, 1, m, a[i], m, 1);
ans += (T.Min[1] >= 0);
T.modify(1, 1, m, a[i - m + 1], m, -1);
}
printf("%d\n", ans);
return 0;
}