ディレクトリ
@説明@
系列{BI}を有する長さmの長さn {AI}の列の所定の数、{aiは}マッチの連続する長さmのサブシリーズ{BI}の数を見つけます。
スキームがある場合のみと二つの列の数がオフにペアリングすることができる場合、2つの列は、一致させることができます。
2つの数字がペアリングすることができ、そして、彼らは時間未満でない場合に限ります。
入力フォーマット
三つの整数N、M、Hの最初の行の。
第二行は、M番号B1、B2、···、BMを有しています。
第3段目は、A1、A2、...、N有する数字。
出力フォーマットは、
サブ列の長さの連続した数のm個のディジタル{AIは} {BI}に一致させることができる出力します。
サンプル
サンプル入力1
。5 10 2
。5。3
。1 5 8 5. 7
サンプル出力1
2
そしてプロンプトデータの範囲は
1 <= M <= nのデータの100%に <= 150000; 1 <= AI、BI、H <= ^ 9 10。
@溶液@
実際には、ここでは二部グラフマッチングを一致させます。
あなたが本当に2部グラフマッチングを書く場合は、このデータ範囲は、あってもエッジが出て構築されていることを恐れています。
しかし、唯一、この質問には半最大マッチングの存在を依頼する必要があり、私たちはホールの定理は、二部グラフの最大マッチングの存在を説明しています。
ホール定理は、点Sのセット左から任意に二部グラフ、Sは、右側の点に取り出される点が接続されているが、近隣T.を構成することを示します 任意Sを満たすためなら| S | <= | T | 、 二部グラフと一致する最大値が存在します。
> | T | - |私たちは、一般的に、時間を使う点の集合は、ホールの定理満たしていないことが判明しようとする必要があります| S |> | T |ポイントSのセット、または同等に表記| Sを 0。
この質問の性質があることに注意してください:AI> = AJ、その後、接続されたAJのBK場合、aiはbkをするために接続することができます。明らかに、この比較、AI + BK> = AJ + BKため > = H。
私たちは明らかにS Tを対応する一意AXの値によって決定され、最大重み値S AX用のセットポイントを設定しました。だから、あなたがしたい場合は| S | - | T |> 0、 それは大きなSを作るために可能な限り、あり、内部のすべてにすべての<=斧Sの最大で見つけることができます。
第一の処理大使をf [I]で表さ+ BJ> =番号BJ hを、愛。
二部グラフのために、我々はO(n)の試験を持っている:すべてのI、統計この二部グラフAJについて<=数pはAI、J、それがPか否かが判断される- [i]がF> 0 、 そうであれば一致することはできません。
彼は、それぞれが唯一の複数の点+の二部グラフの少なくとも1つの点を変更することを指摘し、私たちは速いPを維持し、ツリー行重みに構築することができます- [i]が最大値のF(提示コードをf [I ] - p)が最小となります。
@acceptedコード@
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 150000;
int d[MAXN + 5], dcnt = 0;
int a[MAXN + 5], b[MAXN + 5];
int n, m, h;
struct segtree{
#define lch x<<1
#define rch x<<1|1
struct node{
int l, r;
int tg, mn;
}t[4*MAXN + 5];
void pushup(int x) {t[x].mn = min(t[lch].mn, t[rch].mn);}
void pushdown(int x) {
if( t[x].tg ) {
t[lch].tg += t[x].tg, t[lch].mn += t[x].tg;
t[rch].tg += t[x].tg, t[rch].mn += t[x].tg;
t[x].tg = 0;
}
}
void build(int x, int l, int r) {
t[x].l = l, t[x].r = r, t[x].tg = t[x].mn = 0;
if( l == r ) return ;
int mid = (l + r) >> 1;
build(lch, l, mid), build(rch, mid + 1, r);
}
void modify(int x, int l, int r, int d) {
if( l > t[x].r || r < t[x].l )
return ;
if( l <= t[x].l && t[x].r <= r ) {
t[x].mn += d, t[x].tg += d;
return ;
}
pushdown(x);
modify(x << 1, l, r, d);
modify(x << 1 | 1, l, r, d);
pushup(x);
}
}T;
int main() {
scanf("%d%d%d", &n, &m, &h);
for(int i=1;i<=m;i++)
scanf("%d", &b[i]);
for(int i=1;i<=n;i++)
scanf("%d", &a[i]), d[++dcnt] = a[i];
sort(d + 1, d + dcnt + 1);
dcnt = unique(d + 1, d + dcnt + 1) - d - 1;
T.build(1, 1, dcnt);
for(int i=1;i<=m;i++)
T.modify(1, lower_bound(d + 1, d + dcnt + 1, h - b[i]) - d, dcnt, 1);
for(int i=1;i<=n;i++)
a[i] = lower_bound(d + 1, d + dcnt + 1, a[i]) - d;
for(int i=1;i<=m;i++) T.modify(1, a[i], dcnt, -1);
int ans = (T.t[1].mn >= 0);
for(int i=m+1;i<=n;i++) {
T.modify(1, a[i], dcnt, -1), T.modify(1, a[i-m], dcnt, 1);
ans += (T.t[1].mn >= 0);
}
printf("%d\n", ans);
}
@詳細@
コードFを処理する場合[i]を直接線分ツリー単純な計算です。
その他。。。それの特筆すべき詳細があってはなりません。