loj 6062. 「2017 山东一轮集训 Day2」Pair
给出一个长度为 n 的数列{ ai }和一个长度为mmm的数列{ bi },求{ ai }有多少个长度为 m 的连续子数列能与{ bi }匹配
这个题目和今年西安的k 题非常相似……
首先 bi 的孙序不影响匹配,有hall 定理,二分图存在完全匹配当且仅当对于,集合 X∀X,|N(X)|≥|X| ,再分析 ai , 他能匹配的 bi 一定是一个后缀,反过来考虑 bi 若,对于第 i 的元素,他能匹配的个数为 Ni ,那麽大于 bi 的元素 bj,bj≥bi 能匹配的个数 Nj≥Ni , 因此只要每个集合 1…i,|N(B1…i)|≥|i| 就行,我们维护 Ni−i 的最小值判断它是否大于等于0 就行.
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define INF 0x3f3f3f3f
const int maxn = 1.5e5+10;
typedef pair<int,int> Pair;
typedef long long LL;
int b[maxn],a[maxn];
int n,m,h;
int min_val[maxn<<2],add_val[maxn<<2];
void push_down(int o) {
if(add_val[o]){
int lc = o<<1,rc= o<<1|1;
add_val[lc] += add_val[o];add_val[rc] += add_val[o];
min_val[lc] += add_val[o];min_val[rc] += add_val[o];
add_val[o]=0;
}
}
void add(int L,int R,int x=1,int l=1,int r=m,int o=1) {
if(l>=L && r<=R){
add_val[o] += x;min_val[o]+=x;return;
}
push_down(o);
int mid = (l+r)>>1;
if(L<=mid) add(L,R,x,l,mid,o<<1);
if(R>mid) add(L,R,x,mid+1,r,o<<1|1);
min_val[o] = min(min_val[o<<1],min_val[o<<1|1]);
}
int query(int L,int R,int l=1,int r=m,int o=1){
if(l>=l && r<=R ) return min_val[o];
push_down(o);
int mid = (l+r) >>1,ret = INF;
if(L<=mid) ret = min(query(L,R,l,mid,o<<1),ret);
if(R>mid) ret = min(query(L,R,mid+1,r,o<<1|1),ret);
return ret;
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
// cout.tie(0);
cin>>n>>m>>h;
for(int i=1 ; i<=m ; ++i)cin>>b[i];
for(int i=1 ; i<=n ; ++i)cin>>a[i];
sort(b+1,b+m+1);
for(int i=1 ; i<=m ; ++i)
add(i,i,-i);
int ans =0;
for(int i=1 ; i<=n ; ++i){
int p= lower_bound(b+1,b+m+1,h-a[i]) - b;
add(p,m);
if(i>=m){
if(query(1,m)>=0)ans++;
int p= lower_bound(b+1,b+m+1,h-a[i-m+1]) - b;
add(p,m,-1);
}
}
std::cout << ans << '\n';
return 0;
}