正解:二分+网络流

解题报告:

传送门$QwQ$

这种什么,"同时增加",长得就挺网络流的$QwQ$?然后看到问至少加多少次,于是考虑加个二分呗?于是就大体确定了做题方向,用的网络流+二分

然后就考虑怎么建图呗$QwQ$

首先考虑二分出每个点的值,然后就可以根据这个值求出每个点要增加的多少以及总的修改次数

然后相邻显然考虑黑白染色黑连$S$白连$T$彼此之前连$inf$,跑个最大流判断跑满了没有.

感觉好像要做完辣?

但是这时候要注意到一个问题$QwQ$,就说不能证明这个次数有可二分性$kk$

考虑如果$n\cdot m$为偶数,那显然可二分,因为如果$d$是可行的,那给每个格子都加一就变成了$d+1$显然也可行.

但是如果$n\cdot m$为奇数,发现当$d$可行时并不一定$d+1$可行,,,$QAQ$所以考虑当$n\cdot m$为奇数的时候换一种考虑方法?$QwQ$

考虑设$num_{0/1},sum_{0/1}$表示黑白格的数量和分别的$a$之和,$x$表示最终每个数的值,因为每次一定是一黑一白同时加,所以有$num_{0}\cdot x=sum_{0},num_{1}\cdot x=sum_{1}$,然后可以直接解出$x$然后$check$下就好$QwQ$

$over$!

$upd:$

一周过去我又回来看这题辣,,,$QwQ$

昂说下$T$哪儿了趴

就有个很有效的优化,是在$dinic$中当$flow=0$的时候就可以直接$return$了,,,我挂这儿好多次,,,$QAQ$

 

洛谷$P5038\ [SCOI2012]$奇怪的游戏 二分+网络流洛谷$P5038\ [SCOI2012]$奇怪的游戏 二分+网络流
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#define int long long
#define gc getchar()
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define n(i) edge[i].nxt
#define ri register int
#define rb register int
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];~i;i=n(i))

const int N=100000+50,M=40+10,inf=(ll)3e15;
int n,m,dep[N],head[N],cur[N],S,T,ed_cnt=-1,l,r,d,a[M][M],sum[2],tot[2],as;
int mvx[4]={0,0,1,-1},mvy[4]={1,-1,0,0};
struct ed{int to,nxt,wei;}edge[N<<1];

il int max(ri x,ri y){return x>y?x:y;}
il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il int nam(ri x,ri y){return (x-1)*m+y;}
il void ad(ri x,ri y,ri z)
{edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;edge[++ed_cnt]=(ed){y,head[x],0};head[x]=ed_cnt;}
il bool bfs()
{
    queue<int>Q;Q.push(S);memset(dep,0,sizeof(dep));dep[S]=1;
    while(!Q.empty())
    {
        ri nw=Q.front();Q.pop();
        e(i,nw)if(w(i) && !dep[t(i)]){dep[t(i)]=dep[nw]+1,Q.push(t(i));if(t(i)==T)return 1;}
    }
    return 0;
}
il int dfs(ri nw,ri flow)
{
    if(nw==T || !flow)return flow;ri ret=0;
    for(ri &i=cur[nw];~i;i=n(i))
        if(w(i) && dep[t(i)]==dep[nw]+1)
        {ri tmp=dfs(t(i),min(flow,w(i)));ret+=tmp,w(i)-=tmp;w(i^1)+=tmp,flow-=tmp;if(!flow)return ret;}
    if(!ret)dep[nw]=0;
    return ret;
}
il int dinic(){ri ret=0;while(bfs()){rp(i,S,T)cur[i]=head[i];while(int d=dfs(S,inf))ret+=d;}return ret;}
il bool check(ri x)
{
//    printf("--- check(%d) ---\n",x);
    memset(head,-1,sizeof(head));ed_cnt=-1;ri ret=0;
    rp(i,1,n)
    {
        rp(j,1,m)
        {
            if((i+j)&1)ad(nam(i,j),S,x-a[i][j]),ret+=x-a[i][j];
            else
            {
                ad(T,nam(i,j),x-a[i][j]);
                rp(k,0,3){ri tx=i+mvx[k],ty=j+mvy[k];if(tx && ty && tx<=n && ty<=m)ad(nam(i,j),nam(tx,ty),inf);}
            }
        }
    }
//    printf("--- check(%d) ---\n",x);
    return dinic()==ret;
}

main()
{
    //freopen("5038.in","r",stdin);freopen("5038.out","w",stdout);
    ri tmp=read();
    while(tmp--)
    {
        l=0;r=1ll<<35;n=read();m=read();S=0;T=n*m+1;
        rp(i,1,n)rp(j,1,m)a[i][j]=read(),l=max(l,a[i][j]);
        sum[0]=sum[1]=tot[0]=tot[1]=0;rp(i,1,n)rp(j,1,m)sum[(i+j)&1]+=a[i][j],++tot[(i+j)&1];
        if((n*m)&1)
        {
            ri x=(sum[0]-sum[1])/(tot[0]-tot[1]);
            if(check(x))printf("%lld\n",1ll*x*tot[1]-sum[1]);else printf("-1\n");
        }
        else
        {
            if(sum[0]!=sum[1] || !check(r)){printf("-1\n");continue;}
            while(l<r){ri mid=(l+r)>>1;if(check(mid))r=mid;else l=mid+1;}
            printf("%lld\n",l*tot[1]-sum[1]);
        }
    }
    return 0;
}
View Code

 

相关文章: