zoukankan      html  css  js  c++  java
  • P3488 [POI2009]LYZ-Ice Skates

    传送门

    这一题基础是二分图匹配,并且要知道一个 $Hall$ 定理:对于二分图能完全匹配的充要条件是,设点数少的那边为左边,点数为 $n$,对于 $k in [1,n]$ ,左边任意 $k$ 个点,右边都要有至少有 $k$ 的点与左边这些点相连

    证明好像也不难,首先必要性是显然的

    然后考虑对于左边 $n$ 个点的集合,如果他满足 $Hall$ 定理并且存在一个点 $X_a$ 没法匹配,那么这个点 $X_a$ 连向的 $Y_{b,c,d..}$ 一定已经都有匹配,设此时是 $X_{b,c,d...}$ 匹配 $Y_{b,c,d...}$ ,

    那么由 $Hall$ 定理得到 $X_a,X_{b,c,d...}$ 这些点构成的集合一定还有一条出边连向 $Y_{b,c,d}$ 之外的点(不然 $Y$ 的点数小于 $X$ 的点数),

    所以可以这样一直增广下去最终一定能找到一条增广路

    然后考虑如何保证题目中一定存在完全匹配,显然我们只要考虑连续的一段型号的人,这样会让右边空闲的位置尽量少

    如果不合法那么一定存在连续的一段 $[l,r]$ ,使得 $sum_{i=l}^{r}X_i>(r-l+1+d)*k$ ,其中 $X_i$ 为 $i$ 号脚的人的数量,式子表示人比鞋多

    变一下式子即为 $sum_{i=l}^{r}(X_i-k)>d*k$ ,所以我们只要能判断是否有连续的一段 $X-k$ 的和大于 $d*k$ 

    直接用线段树维护一下最大子段和即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=4e5+7;
    int n,m,K,D;
    struct Segtree {
        ll sum[N<<2],mx[N<<2],lmx[N<<2],rmx[N<<2];
        inline void pushup(int o)
        {
            int lc=o<<1,rc=o<<1|1;
            mx[o]=max( max(mx[lc],mx[rc]) , max(0ll,rmx[lc]+lmx[rc]) );
            lmx[o]=max( max(0ll,lmx[lc]) , sum[lc]+lmx[rc] );
            rmx[o]=max( max(0ll,rmx[rc]) , sum[rc]+rmx[lc] );
            sum[o]=sum[lc]+sum[rc];
        }
        void build(int o,int l,int r)
        {
            if(l==r) { sum[o]=-K; return; }
            int mid=l+r>>1; build(o<<1,l,mid); build(o<<1|1,mid+1,r);
            pushup(o);
        }
        void change(int o,int l,int r,int pos,int v)
        {
            if(l==r) { sum[o]+=v; lmx[o]=rmx[o]=mx[o]=max(0ll,sum[o]); return; }
            int mid=l+r>>1;
            pos<=mid ? change(o<<1,l,mid,pos,v) : change(o<<1|1,mid+1,r,pos,v);
            pushup(o);
        }
        ll query() { return mx[1]; }
    }T;
    int main()
    {
        n=read(),m=read(),K=read(),D=read();
        T.build(1,1,n); int a,b;
        for(int i=1;i<=m;i++)
        {
            a=read(),b=read(); T.change(1,1,n,a,b);
            if(T.query()>1ll*K*D) printf("NIE
    ");
            else printf("TAK
    ");
        }
        return 0;
    }
  • 相关阅读:
    [leetcode] Combination Sum and Combination SumII
    nginx随着passenger构造ruby on rails页
    form 为什么上传文件enctype现场
    ftk学习记录(多形式的文章)
    Android setDisplayOptions 具体的使用说明
    存储结构二叉树
    SQLSERVER存储过程语法的具体解释
    iOS多用连接、反向协议、安全
    struts2于validate要使用
    Oracle存储过程实现返回多个结果集 在构造函数方法中使用 dataset
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11574518.html
Copyright © 2011-2022 走看看