• BZOJ3711 PA2014Druzyny(动态规划+cdq分治+线段树)


      显然可以dp:设f[i]为前i个人最多能分多少组,则f[i]=max{f[j]}+1 (cmax<=i-j<=dmin)。

      容易发现d的限制是一段连续区间,二分或者随便怎么搞都行。c则有点麻烦,考虑分治。找到区间中c最大的位置,处理左边区间再向右边(包括该位置)转移,最后处理右边区间(当然就是cdq分治)。

      考虑怎么转移。设当前区间为[l,r],分段点为k,处理的左边位置为i,右边位置j的限制区间为[aj,j-1],aj单调不降。若i能更新j,则满足i+ck<=j且i>=aj显然j<l+ckaj>=k的点是无法被转移到的。

      讨论一波。对于aj<=l的区间,开始一段右端点每次+1,查询一次后每次O(1)更新;后面一段都是整个区间转移,直接在线段树上打标记。这样保证了是O(较小区间),也就保证了分治的复杂度。a[j]>l的暴力在线段树上查询,因为对于每个j这只会出现一次,复杂度也很正确。

      不停地调分治结果发现线段树不停出锅,可能连线段树都不会写了,没救。(当然发现分治也出锅了

      非常卡空间。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 1000010
    #define P 1000000007
    int n,c[N],d[N],tree1[N<<2];
    priority_queue<int,vector<int>,greater<int> > q,qdel;
    void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
    struct data{int x,y;}tree[N<<2],lazy[N<<2],f[N];
    void upd(data &a,data b)
    {
        if (b.x>a.x) a=b;
        else if (b.x==a.x) inc(a.y,b.y);
    }
    void down(int k,int L,int R)
    {
        int mid=L+R>>1;
        upd(tree[k<<1],(data){lazy[k].x,1ll*(mid-L+1)*lazy[k].y%P});
        upd(tree[k<<1|1],(data){lazy[k].x,1ll*(R-mid)*lazy[k].y%P});
        upd(lazy[k<<1],lazy[k]);
        upd(lazy[k<<1|1],lazy[k]);
        lazy[k]=(data){0,0};
    }
    data merge(data p,data q)
    {
        if (p.x<0&&q.x<0) return p;
        if (p.x>q.x) return p;
        else if (p.x<q.x) return q;
        return (data){p.x,(p.y+q.y)%P};
    }
    data query(int k,int l,int r,int L,int R)
    {
        if (l>r) return (data){-N,0};
        if (L==l&&R==r) return tree[k];
        if (lazy[k].x) down(k,L,R);
        int mid=L+R>>1;
        if (r<=mid) return query(k<<1,l,r,L,mid);
        else if (l>mid) return query(k<<1|1,l,r,mid+1,R);
        else return merge(query(k<<1,l,mid,L,mid),query(k<<1|1,mid+1,r,mid+1,R));
    }
    void modify(int k,int l,int r,data p,int L,int R)
    {
        if (l>r) return;
        if (L==l&&R==r)
        {
            if (p.x>tree[k].x) tree[k].x=p.x,tree[k].y=1ll*p.y*(r-l+1)%P,lazy[k]=p;
            else if (p.x==tree[k].x) inc(tree[k].y,1ll*p.y*(r-l+1)%P),lazy[k].x=p.x,inc(lazy[k].y,p.y);
            return;
        }
        if (lazy[k].x) down(k,L,R);
        int mid=L+R>>1;
        if (r<=mid) modify(k<<1,l,r,p,L,mid);
        else if (l>mid) modify(k<<1|1,l,r,p,mid+1,R);
        else modify(k<<1,l,mid,p,L,mid),modify(k<<1|1,mid+1,r,p,mid+1,R);
        tree[k]=merge(tree[k<<1],tree[k<<1|1]);
    }
    int query2(int k,int l,int r,int L,int R)
    {
        if (L==l&&R==r) return tree1[k];
        int mid=L+R>>1;
        if (r<=mid) return query2(k<<1,l,r,L,mid);
        else if (l>mid) return query2(k<<1|1,l,r,mid+1,R);
        else
        {
            int x=query2(k<<1,l,mid,L,mid),y=query2(k<<1|1,mid+1,r,mid+1,R);
            if (c[x]>c[y]) return x;else return y;
        }
    }
    void build(int k,int l,int r)
    {
        if (l==r) {tree1[k]=l;tree[k]=f[l];return;}
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        tree1[k]=c[tree1[k<<1]]>c[tree1[k<<1|1]]?tree1[k<<1]:tree1[k<<1|1];
        tree[k]=merge(tree[k<<1],tree[k<<1|1]);
    }
    void pre()
    {
        int x=0;
        for (int i=1;i<=n;i++)
        {
            q.push(d[i]);
            while (!qdel.empty()&&q.top()==qdel.top()) q.pop(),qdel.pop();
            while (q.top()+x<i) qdel.push(d[++x]);
            tree1[i]=x;
        }
        while (!q.empty()) q.pop();
        while (!qdel.empty()) qdel.pop();
        for (int i=1;i<=n;i++) d[i]=tree1[i];
        build(1,0,n);
    }
    void solve(int l,int r)
    {
        if (l==r&&l)
        {
            data p=query(1,l,l,0,n);
            if (p.x<=f[l].x) modify(1,l,l,f[l],0,n);
            if (p.x>=f[l].x) upd(f[l],p);
        }
        if (l>=r) return;
        int k=query2(1,l+1,r,0,n);
        solve(l,k-1);
        if (d[k]<k)
        {
            data p=query(1,l,k-c[k]-1,0,n);
            for (int i=max(l+c[k],k);i<=r&&d[i]<=l&&i<=k-1+c[k];i++)
            {
                upd(p,f[i-c[k]]);
                upd(f[i],(data){p.x+1,p.y});
            }
            int L=k,R=r,t=k-1;
            while (L<=R)
            {
                int mid=L+R>>1;
                if (d[mid]<=l) t=mid,L=mid+1;
                else R=mid-1;
            }
            modify(1,k+c[k],t,(data){p.x+1,p.y},0,n);
            for (int i=t+1;d[i]<=k-1&&i<=r;i++)
            {
                p=query(1,d[i],min(i-c[k],k-1),0,n);
                upd(f[i],(data){p.x+1,p.y});
            }
        }
        solve(k,r);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3711.in","r",stdin);
        freopen("bzoj3711.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();
        for (int i=1;i<=n;i++) c[i]=read(),d[i]=read();
        f[0].x=0,f[0].y=1;
        for (int i=1;i<=n;i++) f[i].x=-N,f[i].y=0;
        pre();
        solve(0,n);
        if (f[n].x>=0) cout<<f[n].x<<' '<<f[n].y<<endl;
        else cout<<"NIE";
        return 0;
    }
  • 相关阅读:
    *** FATAL ERROR L250: CODE SIZE LIMIT IN RESTRICTED VERSION EXCEEDED
    *** FATAL ERROR L250: CODE SIZE LIMIT IN RESTRICTED VERSION EXCEEDED
    nRF24L01无线介绍
    关于使用墙外安卓应用
    jquery miniui , 普加甘特图,流程管理
    数据库测试DbUnit
    如何写BaseDomain
    js 字符串转 数字
    Http协议中 常用的参数应用
    spring 管理 jdbc 事务
  • 原文地址:https://www.cnblogs.com/Gloid/p/9729908.html
Copyright © 2020-2023  润新知