• 「2017 山东一轮集训 Day2」Pair (霍尔定理+线段树)


    题目描述

    给出一个长度为  的数列  和一个长度为  的数列 ,求  有多少个长度为  的连续子数列能与  匹配。

    两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当且仅当它们的和不小于 

    输入格式

    第一行三个数字 
    第二行有  个数字 
    第三行有  个数字 

    输出格式

    输出一个数字, 有多少个长度为  的连续子数列能与  匹配。

    样例

    样例输入 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
    ", ans);
        return 0;
    }
    

      

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    工具
    选择排序
    c#中queue的用法
    c#加密
    话谈c#拷贝
    const与readonly的区别
    WinForm中使MessageBox实现可以自动关闭功能
    c#winform关闭窗口时触发的事件
    委托
    C# STA和MTA线程设置
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/11270793.html
Copyright © 2020-2023  润新知