• P4890 Never·island(dp)


    P4890 Never·island

    求门开的最小时间,其实也就是求门关的最大时间。

    坐标这么大....显然坐标要离散化

    离散化排序后,我们发现x轴被这些点划分成若干条线段$(l,r)$,并且有4种情况

    我们用$v[i]$数组表示给队$i$钥匙的贡献

    1.左端点为$i$队的起点,右端点为$i$队的终点:显然队$i$钥匙的贡献包括这一段,$v[i]+=r-l$

    2.左端点为$i$队的终点,右端点为$j$队的起点:无论如何分配钥匙,这一段都可以关门,于是答案可直接算上$r-l$

    3.左端点为$i$队的终点,右端点为$j$队的终点:如果我们给$j$队钥匙,$i$队就可以关门,$v[j]+=r-l$

    4.左端点为$i$队的起点,右端点为$j$队的终点:我们只有给$i,j$各一把钥匙,才能算上这一段的贡献

    于是我们就在$i,j$之间先连边,边权为$r-l$

    蓝后我们又发现,这些点由一些互不相干的链组成。

    于是我们按$x轴$从左到右dfs一遍求出dp的优先顺序

    最后我们用$f[i][j][0/1]$表示前$i$个点,已给$j$个点钥匙,是否选择了第$i$个(当前)点的最优解

    这就是一个二维dp辣

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define rint register int
    using namespace std;
    inline int Max(int a,int b){return a>b?a:b;}
    inline int Min(int a,int b){return a<b?a:b;}
    void read(int &x){
        char c=getchar();x=0;
        while(c<'0'||c>'9') c=getchar();
        while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
    }
    #define N 4005
    int n,m,pos[N],tp,h[N],nxt[N],v[N],sv[N];
    int f[N][N][2],tot; bool vis[N];
    map <int,int> mp;
    void dfs(int x){vis[h[++tp]=x]=1; if(nxt[x])dfs(nxt[x]);}
    int main(){
        read(n);read(m); int l,r,L,R,tn=n<<1;
        for(rint i=1;i<=n;++i){
            read(l), read(r);
            pos[i]=l, pos[i+n]=r;
            mp[l]=i<<1, mp[r]=i<<1|1;
        }sort(pos+1,pos+tn+1);//离散化
        for(rint i=1;i<tn;++i){
            l=pos[i], r=pos[i+1];
            L=mp[l], R=mp[r];
            if((L&1)&&(R&1)) v[R>>1]+=r-l;
            if((L&1)&&!(R&1)) tot+=r-l;
            if(!(L&1)&&!(R&1)) v[L>>1]+=r-l;
            if(!(L&1)&&(R&1)){
                if((L>>1)==(R>>1)) v[L>>1]+=r-l;
                else nxt[R>>1]=L>>1,sv[R>>1]=r-l;
            }
        }
        for(rint i=1;i<=tn;++i){
            int p=mp[pos[i]];
            if(!(p&1)&&!vis[p>>1]) dfs(p>>1);
        }//dfs确定dp顺序
        memset(f,0xbf,sizeof(f));//-inf
        f[n+1][0][0]=0;
        for(rint i=n;i;--i){
            f[i][0][0]=0;
            for(rint j=Min(n-i+1,m);j;--j){
                f[i][j][0]=Max(f[i+1][j][0],f[i+1][j][1]);
                f[i][j][1]=Max(f[i+1][j-1][0],f[i+1][j-1][1]+sv[h[i]])+v[h[i]];
            }
        }printf("%d",pos[tn]-pos[1]-tot-Max(f[1][m][1],f[1][m][0]));
        return 0;
    }

     

  • 相关阅读:
    Unix系统编程():分散输入和集中输出(Scatter-Gather IO):readv和writev
    Unix系统编程()在文件特定偏移量处的IO:pread和pwrite
    Unix系统编程()复制文件描述符
    Unix系统编程()文件描述符和打开文件之间的关系
    主存到Cache直接映射、全相联映射和组相联映射
    Unix系统编程()文件控制操作fcntl
    Unix系统编程()原子操作和竞争条件
    Unix系统编程()深入探究文件IO概述
    Unix系统编程()main函数的命令行参数
    Unix系统编程()通用模型以外的操作ioctl
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10673322.html
Copyright © 2020-2023  润新知