zoukankan      html  css  js  c++  java
  • SCOI2012 奇怪的游戏

    在中医药的(ACM)中做到了,是(M)题.
    那场比赛被打自闭了(QAQ)
    题目链接


    这道题一看就知道是一个网络流模型
    建模也是比较典型的方式.
    因为我们选两个相邻的格子,因此我们把它黑白染色,记录(4)个量:白点个数(c_w),黑点个数(c_b),白点之和(s_w),黑点之和(s_b).
    假设最终所有的高度都是(h).一次操作会把一个黑点(+1),也会把一个白点(+1).
    我们列出方程:(h*c_b-s_b=h*c_w-s_w)
    简单移个项得(h*(c_b-c_w)=s_b-s_w)
    那么,(h=frac{s_b-s_w}{c_b-c_w})
    假设(c_b-c_w)不为(0),如果(s_b-s_w)不为(c_b-c_w)的倍数就无解.
    否则就把(h)算出来然后(check)一下.
    具体如何(check)后文会说.
    如果(c_b-c_w=0),那么如果(s_b-s_w)不为(0)也无解.
    如果为(0)怎么办呢?
    首先,若(c_b-c_w=0),那么(n,m)中肯定有一个偶数.
    假设我们可以找到一个答案(x),那么(x+1)也肯定是答案(因为(n,m)中有一个偶数)
    因此我们可以二分.
    首先二分一个(x),然后用网络流(check).
    这个和上文的(check)是一样的.
    我们让源点(S)向所有黑点((i,j))连边,容量是(x-w_{i,j})
    然后我们让所有黑点和相邻的白点连边,容量是(INF)
    然后我们让所有白点((i,j))向汇点(T)连边,容量是(x-w_{i,j})
    对于每单位的流,肯定通过某个黑点,某个白点,然后到(T).
    这等价于我们操作一次.
    那么只要记录一下(V=sum_{(i,j)is black}x-w_{i,j})
    然后跑一个最大流,看看答案是不是(V)即可.

    代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #define N (1621)
    #define M (4000001)
    #define inf (1e16)
    #define rg register int
    #define Label puts("NAIVE")
    #define spa print(' ')
    #define ent print('
    ')
    #define rand() (((rand())<<(15))^(rand()))
    typedef long double ld;
    typedef long long LL;
    typedef unsigned long long ull;
    using namespace std;
    inline char read(){
    	static const int IN_LEN=1000000;
    	static char buf[IN_LEN],*s,*t;
    	return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
    }
    template<class T>
    inline void read(T &x){
    	static bool iosig;
    	static char c;
    	for(iosig=false,c=read();!isdigit(c);c=read()){
    		if(c=='-')iosig=true;
    		if(c==-1)return;
    	}
    	for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
    	if(iosig)x=-x;
    }
    inline char readchar(){
    	static char c;
    	for(c=read();!isalpha(c);c=read())
    	if(c==-1)return 0;
    	return c;
    }
    const int OUT_LEN = 10000000;
    char obuf[OUT_LEN],*ooh=obuf;
    inline void print(char c) {
    	if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
    	*ooh++=c;
    }
    template<class T>
    inline void print(T x){
    	static int buf[30],cnt;
    	if(x==0)print('0');
    	else{
    		if(x<0)print('-'),x=-x;
    		for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
    		while(cnt)print((char)buf[cnt--]);
    	}
    }
    inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
    #define int LL
    int W,n,m,a[41][41],fi[N],ne[M],b[M],S,T,q[N],h,t,d[N],vh[N],E,c[M];
    void add(int x,int y,LL z){
    	ne[++E]=fi[x],fi[x]=E,b[E]=y,c[E]=z;
    	ne[++E]=fi[y],fi[y]=E,b[E]=x,c[E]=0;
    }
    void getdis(){
        h=t=0,q[++t]=T;
        while(h<t){
            int u=q[++h];
            for(int i=fi[u];i;i=ne[i]){
                int v=b[i];
                if(d[v]||v==T)continue;
                d[v]=d[u]+1,q[++t]=v;
            }
        }
    }
    int dfs(int u,LL Flow){
        if(u==T)return Flow;
        LL res=Flow;
        int mindist=n*m+2;
        for(int i=fi[u];i;i=ne[i])
        if(c[i]){
            int v=b[i],nega=i^1;
            if(d[u]==d[v]+1){
                int x=dfs(v,min(res,1ll*c[i]));
                res-=x,c[i]-=x,c[nega]+=x;
                if(d[S]==n)return Flow-res;
                if(!res)break;
            }
            mindist=min(d[v],mindist);
        }
        if(Flow==res){
            vh[d[u]]--;
            if(!vh[d[u]])d[S]=n*m+2;
            else d[u]=mindist+1,vh[d[u]]++;
        }
        return Flow-res;
    }
    bool check(LL x){
    	int cnt=0;LL V=0; E=1;
    	S=n*m+1,T=(n*m)+2;
    	memset(fi,0,sizeof(fi));
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			cnt++;
    			if(((i+j)&1)==0){
    				V+=1ll*(x-a[i][j]);
    				add(S,cnt,x-a[i][j]);
    				if(j<m)add(cnt,cnt+1,inf);
    				if(i<n)add(cnt,cnt+m,inf);
    				if(j>1)add(cnt,cnt-1,inf);
    				if(i>1)add(cnt,cnt-m,inf);
    			}
    			else add(cnt,T,x-a[i][j]);
    		}
    	for(int i=1;i<=n*m+2;i++)d[i]=0;
    	getdis(); LL ans=0;
    	for(int i=0;i<=n*m+2;i++)vh[i]=0;
    	for(int i=1;i<=n*m+2;i++)vh[d[i]]++;
    	while(d[S]<n*m+2)ans+=dfs(S,inf);
    	return (ans==V); 
    }
    signed main(){
    	read(W);
    	while(W--){
    		int cntb=0,cntw=0,sb=0,sw=0,mx=0;
    		read(n),read(m);
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=m;j++){
    				read(a[i][j]),mx=max(mx,a[i][j]);
    				if(!((i+j)&1))cntb++,sb+=a[i][j];
    				else cntw++,sw+=a[i][j];
    			}
    		if(cntb!=cntw){
    			int x=(sb-sw)/(cntb-cntw);
    			if(x>=mx&&check(x))print(x*cntw-sw),ent;
    			else print(-1),ent; continue;
    		}
    		if(sb!=sw){print(-1),ent;continue;}
    		LL L=mx,R=inf/2,ans=-1;
    		while(L<=R){
    			LL mid=(L+R)>>1;
    			if(check(mid))R=mid-1,ans=mid;
    			else L=mid+1;
    		}
    		print(ans*cntw-sw),ent;
    	}
    	return flush(),0;
    }
    
  • 相关阅读:
    FastDFS 集群 安装 配置
    springboot 集成fastDfs
    分布式文件系统FastDFS详解
    上传下载
    Spring Boot:上传文件大小超限制如何捕获 MaxUploadSizeExceededException 异常
    MySQL报错解决方案:2013-Lost connection to MySQL server
    JWT与Session比较和作用
    html跑马灯/走马灯效果
    后端排序,debug模式中map的顺序出错
    js调用后台接口进行下载
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10173488.html
Copyright © 2011-2022 走看看