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;
    }
    
  • 相关阅读:
    (网页)中的简单的遮罩层
    (后端)shiro:Wildcard string cannot be null or empty. Make sure permission strings are properly formatted.
    (网页)jQuery的时间datetime控件在AngularJs中使用实例
    Maven Myeclipse 搭建项目
    MyBatis 环境搭建 (一)
    java 常用方法
    XML 基础
    JS BOM
    js 事件
    js 的使用原则
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10173488.html
Copyright © 2011-2022 走看看