bzoj2406 矩阵 二分+有源汇上下界网络流

来源:互联网 发布:晋江 小说 推荐 知乎 编辑:程序博客网 时间:2024/05/19 16:06

题意略。

%%ymw大神,考场上直接切。
先二分答案。
然后连边,先预处理一下横行纵行的前缀和,然后b的每行每列取值范围就是r[i]-mid,r[i]+mid,列同理。
那么我们把横行和纵行看做点,拆成两部分形成一个二分图,横行纵行之间连边,容量为(r[i]-mid,r[i]+mid),列同理。
然后跑可行流来判断。
如果要求输出答案的话提前记录一下就好了。

#include<cstdio>#include<algorithm>#include<cstring>#include<map>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=4e5+5;int n,m;int head[N],go[N],next[N],cur[N],val[N];int tot=1;int num[300][300];const int inf=0x3f3f3f3f;int cnt,s,t,S,T,L,R;int dis[N],q[N],du[N];int row[N],col[N];inline void clear(){    tot=1;    memset(head,0,sizeof(head));    memset(du,0,sizeof(du));    s=0,t=n+m+1,S=n+m+2,T=n+m+3;}inline void ins(int x,int y,int z){    go[++tot]=y;    next[tot]=head[x];    val[tot]=z;    head[x]=tot;}inline void add(int x,int y,int z){    ins(x,y,z);    ins(y,x,0);}inline bool bfs(){    int t=0,w=1;    memset(dis,-1,sizeof(dis));    q[1]=S,dis[S]=0;    while (t<w)    {        int x=q[++t];        for(int i=head[x];i;i=next[i])        {            int v=go[i];            if (val[i]&&dis[v]==-1)            {                dis[v]=dis[x]+1;                q[++w]=v;                if (v==T)return 1;            }        }    }    return 0;}inline int dfs(int x,int f){    if (x==T||!f)return f;    int w,used=0;    for(int i=cur[x];i;i=next[i])    {        int v=go[i];        if (dis[v]==dis[x]+1)        {            w=f-used;            w=dfs(v,min(w,val[i]));            val[i]-=w;            val[i^1]+=w;            used+=w;            if (used==f)break;         }    }    return used;}inline int dinic(){    int ans=0;    while (bfs())    {        fo(i,0,T)cur[i]=head[i];        ans+=dfs(S,inf);    }    return ans;}bool pd(int mid){    clear();    add(t,s,inf);    fo(i,1,n)    fo(j,1,m)    add(i,j+n,R-L),du[i]-=L,du[j+n]+=L,num[i][j]=tot;    fo(i,1,n)    {        int p=max(0,row[i]-mid),q=mid+row[i];        add(s,i,q-p);        du[s]-=p,du[i]+=p;    }    fo(i,1,m)    {        int p=max(0,col[i]-mid),q=mid+col[i];        add(i+n,t,q-p);        du[i+n]-=p,du[t]+=p;    }    int cnt=0;    fo(i,s,t)    if (du[i]>0)add(S,i,du[i]),cnt+=du[i];    else if (du[i]<0)add(i,T,-du[i]);    return dinic()==cnt;}int main(){    scanf("%d%d",&n,&m);    fo(i,1,n)    {        fo(j,1,m)        {            int x;            scanf("%d",&x);            row[i]+=x,col[j]+=x;        }    }    scanf("%d%d",&L,&R);    int ans=-1;    int l=0,r=200000;    while (l<=r)    {        int mid=(l+r)>>1;        if (pd(mid))r=mid-1,ans=mid;        else l=mid+1;    }    printf("%d\n",ans);}
阅读全文
0 0
原创粉丝点击