zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    AtCoder Beginner Contest 205
    Codeforces Round #725 (Div. 3)
    Educational Codeforces Round 110 (Rated for Div. 2)【A
    Codeforces Round #722 (Div. 2)
    AtCoder Beginner Contest 203(Sponsored by Panasonic)
    AISing Programming Contest 2021(AtCoder Beginner Contest 202)
    PTA 520 钻石争霸赛 2021
    Educational Codeforces Round 109 (Rated for Div. 2)【ABCD】
    AtCoder Beginner Contest 200 E
    Educational Codeforces Round 108 (Rated for Div. 2)【ABCD】
  • 原文地址:https://www.cnblogs.com/Gloid/p/9729908.html
Copyright © 2011-2022 走看看