• AGC031E Snuke the Phantom Thief


    Link
    枚举偷了几个珠宝,然后求出按横/纵坐标升序排序之后第(i)个珠宝的合法横/纵坐标范围。
    每个珠宝拆成入点出点,入点到出点有一条流量为(1)费用为价值的边。
    然后再建(k)个坐标出/入点,分别和源/汇点连边,其中第(i)个出/入点代表按按横/纵坐标升序排序之后的第(i)个珠宝,它和横/纵坐标在该范围内的入/出点连边。这些边都是流量为(1)费用为(0)
    那么我们会建出一个源点( ightarrow)坐标出点( ightarrow)珠宝入点( ightarrow)珠宝出点( ightarrow)坐标入点( ightarrow)汇点的分层图,求最大费用最大流就行了。

    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using i64=long long;
    const int V=327,E=26087;const i64 inf=1e18;
    int n,m,s,t,tot,head[V],vis[V];i64 cost,dis[V];
    struct edge{int v,f;i64 c;int next;}e[E];
    struct node{int x,y;i64 v;}p[V];
    struct opt{int o,a,b;}op[V];
    int read(){int x=0;int c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
    i64 raed(){i64 x=0;int c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
    void add(int u,int v,int f,i64 c){e[++tot]={v,f,c,head[u]},head[u]=tot,e[++tot]={u,0,-c,head[v]},head[v]=tot;}
    int update()
    {
        i64 mn=inf;
        for(int u=1;u<=t;++u) if(vis[u]) for(int i=head[u];i;i=e[i].next) if(!vis[e[i].v]&&e[i].f) mn=std::min(mn,dis[e[i].v]+e[i].c-dis[u]);
        if(mn==inf) return 0;
        for(int u=1;u<=t;++u) if(vis[u]) dis[u]+=mn;
        return 1;
    }
    int dfs(int u,int res)
    {
        if(u==t) return cost-=dis[s]*res,res;
        int use=0;vis[u]=1;
        for(int i=head[u],t;i;i=e[i].next)
    	if(!vis[e[i].v]&&e[i].f&&dis[u]==dis[e[i].v]+e[i].c)
    	{
    	    t=dfs(e[i].v,std::min(res-use,e[i].f)),use+=t,e[i].f-=t,e[i^1].f+=t;
    	    if(use==res) return use;
    	}
        return use;
    }
    void solve(int k)
    {
        static int lx[V],rx[V],ly[V],ry[V];
        tot=1,cost=0,s=2*k+2*n+1,t=s+1,memset(head+1,0,t<<2),memset(dis+1,0,t<<3);
        memset(lx+1,0,k<<2),memset(ly+1,0,k<<2),memset(rx+1,0x7f,k<<2),memset(ry+1,0x7f,k<<2);
        for(int i=1;i<=k;++i) add(s,i,1,0),add(i+n+n+k,t,1,0);
        for(int i=1;i<=n;++i) add(i+k,i+n+k,1,-p[i].v);
        for(int i=1;i<=m;++i)
    	switch(op[i].o)
    	{
    	case'U':for(int j=1;j<=k-op[i].b;++j)ry[j]=std::min(ry[j],op[i].a-1);break;
    	case'D':for(int j=op[i].b+1;j<=k;++j)ly[j]=std::max(ly[j],op[i].a+1);break;
    	case'L':for(int j=op[i].b+1;j<=k;++j)lx[j]=std::max(lx[j],op[i].a+1);break;
    	case'R':for(int j=1;j<=k-op[i].b;++j)rx[j]=std::min(rx[j],op[i].a-1);break;
    	}
        for(int i=1;i<=k;++i) for(int j=1;j<=n;++j) if(lx[i]<=p[j].x&&p[j].x<=rx[i]) add(i,j+k,1,0);
        for(int i=1;i<=k;++i) for(int j=1;j<=n;++j) if(ly[i]<=p[j].y&&p[j].y<=ry[i]) add(j+n+k,i+n+n+k,1,0);
        do do memset(vis+1,0,t<<2);while(dfs(s,1e9));while(update());
    }
    int main()
    {
        i64 ans=0;
        n=read();for(int i=1;i<=n;++i) p[i]={read(),read(),raed()};
        m=read();for(int i=1;i<=m;++i) op[i]={getchar(),read(),read()};
        for(int k=1;k<=n;++k) solve(k),ans=std::max(ans,cost);
        printf("%lld",ans);
    }
    
  • 相关阅读:
    2015年终总结
    mmzb游戏事故分析
    为sproto手写了一个python parser
    Lua小技巧
    Techparty-广州 10 月 31 日 Docker 专场沙龙 后记
    1password密码库格式更新
    SSL加密与系统时间
    webpack的学习使用三
    webpack的学习使用二
    webpack的学习使用一
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12747557.html
Copyright © 2020-2023  润新知