zoukankan      html  css  js  c++  java
  • [NOI2011]Noi嘉年华

     [NOI2011]Noi嘉年华 

    把若干区间分成两个集合(可以有的区间不放在任意集合中),使得任意的a∈A,b∈B,a、b区间没有交集

    求较小集合最大能是多少

    n<=200

    区间不交,直接处理只能状压了吧。。。排序什么的都没有用

    但是发现,区间一定是一段黑色,一段白色

    n<=200

    把一段直接分配给某种颜色!

    离散化先,

    in[l][r]完全在(l,r)中的区间

    pre[i][j],(1,i),某个集合选择了j个,另一个集合最大选择多少。转移时候枚举最后一段都给一个集合

    bac[i][j],(i,T),.....同理

    第一问就是:max(pre[T][i],i)

    第二问:

    强制必须选择,那么这个区间一定被某个连续段包含。枚举连续段

    先设:f[l][r],强制完全在[l,r]中的区间都给某个集合时,最小的集合最大能是多少

    枚举左右各选择几个,用min(x+in[l][r]+y,pre[l][x]+bac[r][y])更新

    O(n^4)

    发现x不变时,y作为自变量,x+in[l][r]+y是增函数,而pre[l][x]+bac[r][y]是减函数

    所以,x变大,y必须变小,整个min才可能更大

    决策单调性!

    O(n^3logn)

    进一步发现,整个min函数是单峰的函数,所以下一个不优的时候直接break

    对y维护指针平移。

    (一般决策单调性绝对不能这么做)

    O(n^3)

    Code:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=402;
    const int inf=0x3f3f3f3f;
    int n,l[N],r[N],c[N],tot;
    int in[N][N],pre[N][N],bac[N][N],f[N][N];
    ll ans=0;
    int main(){
        rd(n);
        for(reg i=1;i<=n;++i){
            rd(l[i]);rd(r[i]);
            r[i]=l[i]+r[i];
            c[++tot]=l[i];c[++tot]=r[i];
        }
        sort(c+1,c+tot+1);
        tot=unique(c+1,c+tot+1)-c-1;
        for(reg i=1;i<=n;++i){
            l[i]=lower_bound(c+1,c+tot+1,l[i])-c;
            r[i]=lower_bound(c+1,c+tot+1,r[i])-c;
    //        cout<<l[i]<<" and "<<r[i]<<endl;
        }
        for(reg i=1;i<=tot;++i){
            for(reg j=i+1;j<=tot;++j){
                for(reg k=1;k<=n;++k){
                    if(l[k]>=i&&r[k]<=j) ++in[i][j];
                }
            }
        }
    //    for(reg i=1;i<=tot;++i){
    //        for(reg j=1;j<=tot;++j){
    //            cout<<i<<" "<<j<<" : "<<in[i][j]<<endl;
    //        }
    //    }
        memset(pre,-inf,sizeof pre);
        memset(bac,-inf,sizeof bac);
        pre[1][0]=0;
        for(reg i=1;i<=tot;++i){
            for(reg j=0;j<=n;++j){
                for(reg k=1;k<i;++k){
                    pre[i][j]=max(pre[i][j],pre[k][j]+in[k][i]);
                    if(j>=in[k][i]) pre[i][j]=max(pre[i][j],pre[k][j-in[k][i]]);
                }
    //            cout<<" i j "<<i<<" "<<j<<" : "<<pre[i][j]<<endl;
            }
        }
    //    cout<<"---------------------------------------------------------"<<endl;
        bac[tot][0]=0;
        for(reg i=tot;i>=1;--i){
            for(reg j=0;j<=n;++j){
                for(reg k=i+1;k<=tot;++k){
                    bac[i][j]=max(bac[i][j],bac[k][j]+in[i][k]);
                    if(j>=in[i][k]) bac[i][j]=max(bac[i][j],bac[k][j-in[i][k]]);
                }
    //            cout<<" i j "<<i<<" "<<j<<" : "<<bac[i][j]<<endl;
            }
        }
        
        for(reg j=0;j<=n;++j){
            ans=max(ans,(ll)min(j,pre[tot][j]));
        }
        cout<<ans<<endl;
        
        for(reg l=1;l<=tot;++l){
            for(reg r=l+1;r<=tot;++r){
                int y=n;
                for(reg x=0;x<=n;++x){
                    while(y&&min(x+in[l][r]+y,pre[l][x]+bac[r][y])<=min(x+in[l][r]+y-1,pre[l][x]+bac[r][y-1])) --y;
    //                cout<<" x y "<<x<<" "<<y<<endl;
                    f[l][r]=max(f[l][r],min(x+in[l][r]+y,pre[l][x]+bac[r][y]));
                }        
    //            cout<<" l r "<<l<<" "<<r<<" : "<<f[l][r]<<endl;
            }
        }
        for(reg i=1;i<=n;++i){
            int L=l[i],R=r[i];
            int mx=0;
            for(reg l=L;l>=1;--l){
                for(reg r=R;r<=tot;++r){
                    mx=max(mx,f[l][r]);
                }
            }
            cout<<mx<<endl;
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/4/9 10:31:40
    */
    View Code

     处理区间不交等问题时候,直接做要状压

    不妨强制一段都颜色一致,暴力枚举转移

  • 相关阅读:
    追随自己的价值观:用研经理 Anne Diaz 职业探索之路
    语义化版本(SemVer)的范围
    git如何放弃所有本地修改
    将本地已有的一个项目上传到新建的git仓库的方法
    using supervisord to run lsyncd script
    sersync下载安装及配置(有演示示例)
    sersync+rsync原理及部署
    Rsync+sersync 实现数据实时同步
    在分屏浏览中并排使用两个 Mac App
    MacOS 安装 Astah Professional 7.2
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10681064.html
Copyright © 2011-2022 走看看