• Gym102341B Bulbasaur


    Link
    先利用最大流最小割定理将要求的转化为最小割,然后就可以转化为删掉最少的点使得两层不连通。
    我们先考虑([1,i])层,设(f_{s,j})表示使得第(i)层有且仅有(S)中的点能够到达(j)层,最少需要删掉的点数。
    显然(f_{s,j})关于(j)单调,并且(f_{s,j}in[0,m])
    那么我们升序枚举(i),然后对于同一个(s),维护值不相同的(f_{s,j})(j)之间的分界线。转移是非常简单的。

    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    int n,m,to[10];long long ans;
    struct node
    {
        int pos[10];
        node(){memset(pos,0,40);}
        int&operator[](int x){return pos[x];}
    }f[1<<9],t[1<<9];
    void merge(node&p,node q)
    {
        if(p[0]>q[0]) std::swap(p,q);
        for(int i=m;~i;--i) if(q[i]==q[0]) q[i]=p[0];
        for(int i=1;i<=m;++i) p[i]=std::max(p[i],q[i]);
    }
    node up(node x){for(int i=m;i;--i)x[i]=x[i-1];return x;}
    int get(){char c=getchar();while(!isdigit(c))c=getchar();return c&15;}
    int cal(int s){int r=0;for(int i=0;i<m;++i)if(s>>i&1)r|=to[i];return r;}
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<1<<m;++i) for(int j=0;j<=m;++j) f[i][j]=j<=m-__builtin_popcount(i)? 1:n+1;
        for(int i=2;i<=n;++i)
        {
    	memset(to,0,m<<2);
    	for(int j=0;j<1<<m;++j) for(int k=0;k<=m;++k) t[j][k]=n+1;
    	for(int j=0;j<m;++j) for(int k=0;k<m;++k) if(get()) to[j]|=1<<k;
    	for(int j=0;j<1<<m;++j) merge(t[cal(j)],f[j]);
    	std::swap(f,t);
    	for(int j=(1<<m)-1;j;--j){node r=up(f[j]);for(int k=0;k<m;++k) if(j>>k&1) merge(f[j^1<<k],r);}
    	for(int j=0;j<1<<m;++j) for(int k=0;k<=m-__builtin_popcount(j);++k) f[j][k]=std::min(f[j][k],i);
    	for(int j=1;j<=m;++j) ans+=i-f[0][j];
        }
        printf("%lld",ans);
    }
    
  • 相关阅读:
    第三章 IPtables防火墙基本使用
    第四章 SFTP命令使用
    第三章 AWS快照创建实例启动失败排查解决
    第三章 windows下启动停止服务
    第六章 Sersync实时同步服务介绍
    第四章 IPtables防火墙进阶使用
    倍增求LCA
    求割点
    C. BAString
    E. MEX and Increments
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12708766.html
Copyright © 2020-2023  润新知