bzoj2756: [SCOI2012]奇怪的游戏(网络流+分情况)

2756: [SCOI2012]奇怪的游戏

题目:传送门 

 


 

 

题解:

   发现做不出来的大难题一点一个网络流

   %大佬

   首先黑白染色(原来是套路...)染色之后就可以保证每次操作都一定会使黑白各一个各自的值加1

   那么我们接着统计一下黑白格子个数cnt1和cnt2,以及各自的权值和sum1和sum2

   然后就要分情况讨论了:

   1、在cnt1不等于cnt2的情况下

     假设有解且最终的数值均为ans,那么不难发现:cnt1*ans-cnt2*ans=sum1-sum2(因为每次操作黑白格子的总和同时加1,所以总和差始终不变)

     那就可以直接推导出ans=(sum1-sum2)/(cnt1-cnt2) 那么我们其实就只需要判断一下该值是否合法就OK

   2、cnt1=cnt2

     若sum1不等于sum2 那么一定输出-1,因为差不变啊,显然(不过好像没有这种点)

     若sum1=sum2,那么设最终的数值为ans

     如果ans满足答案,那么ans+1也一定满足,显然存在单调性,直接就二分check

  判断ans是否合法:st连白点,流量ans-d[i][j];黑点连ed,流量ans-d[i][j];相邻的不同颜色的点相连,流量无限;那么只要看看是否满流就好啊。。。

   注意上界有点大...

    


 

 

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 #define inf 999999999999999999
  7 using namespace std;
  8 typedef long long LL;
  9 struct node
 10 {
 11     int x,y,next,other;LL c;
 12 }a[1110000];int len,last[2100];
 13 void ins(int x,int y,LL c)
 14 {
 15     LL k1,k2;
 16     k1=++len;
 17     a[len].x=x;a[len].y=y;a[len].c=c;
 18     a[len].next=last[x];last[x]=len;
 19     
 20     k2=++len;
 21     a[len].x=y;a[len].y=x;a[len].c=0;
 22     a[len].next=last[y];last[y]=len;
 23     
 24     a[k1].other=k2;
 25     a[k2].other=k1;
 26 }
 27 int list[2100],h[2100],st,ed,head,tail;
 28 bool bt_h()
 29 {
 30     memset(h,0,sizeof(h));h[st]=1;
 31     list[1]=st;head=1;tail=2;
 32     while(head!=tail)
 33     {
 34         int x=list[head];
 35         for(int k=last[x];k;k=a[k].next)
 36         {
 37             int y=a[k].y;
 38             if(h[y]==0 && a[k].c>0)
 39             {
 40                 h[y]=h[x]+1;
 41                 list[tail++]=y;
 42             }
 43         }
 44         head++;
 45     }
 46     if(h[ed]>0)return true;
 47     return false;
 48 }
 49 LL find_flow(int x,LL flow)
 50 {
 51     if(x==ed)return flow;
 52     LL s=0,t;
 53     for(int k=last[x];k;k=a[k].next)
 54     {
 55         int y=a[k].y;
 56         if(h[y]==h[x]+1 && a[k].c>0 && s<flow)
 57         {
 58             s+=t=find_flow(y,min(a[k].c,flow-s));
 59             a[k].c-=t;a[a[k].other].c+=t;if(s==flow)break;
 60         }
 61     }
 62     if(s==0)h[x]=0;
 63     return s;
 64 }
 65 int T;
 66 int n,m;
 67 LL mp[110][110];int d[110][110];
 68 bool f[110][110];//黑false白true染色
 69 const int dx[5]={0,-1,1,0,0};
 70 const int dy[5]={0,0,0,-1,1};
 71 bool check(LL sum)
 72 {
 73     LL ret=0;
 74     len=0;memset(last,0,sizeof(last));st=n*m+1,ed=st+1;
 75     for(int i=1;i<=n;i++)
 76         for(int j=1;j<=m;j++)
 77             if(f[i][j]==true)ins(st,d[i][j],sum-mp[i][j]),ret+=sum-mp[i][j];
 78             else ins(d[i][j],ed,sum-mp[i][j]);
 79     for(int i=1;i<=n;i++)
 80         for(int j=1;j<=m;j++)if(f[i][j]==true)
 81             for(int k=1;k<=4;k++)
 82             {
 83                 int tx=i+dx[k],ty=j+dy[k];
 84                 if(d[tx][ty]!=-1 && f[i][j]!=f[tx][ty])ins(d[i][j],d[tx][ty],inf);    
 85             }
 86     LL ans=0;while(bt_h())ans+=find_flow(st,inf);
 87     return ret==ans?true:false;
 88 }
 89 LL sol(LL sum)
 90 {
 91     LL ans=0;
 92     for(int i=1;i<=n;i++)
 93         for(int j=1;j<=m;j++)
 94             ans+=(sum-mp[i][j]);
 95     return ans/2LL;
 96 }
 97 int main()
 98 {
 99     scanf("%d",&T);while(T--)
100     {
101         LL cnt1=0,cnt2=0,sum1=0,sum2=0,maxx=0;
102         scanf("%d%d",&n,&m);memset(mp,0,sizeof(mp));memset(d,-1,sizeof(d));memset(f,true,sizeof(f));
103         int ss=0;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)d[i][j]=++ss;
104         for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%lld",&mp[i][j]),sum1+=mp[i][j],maxx=max(maxx,mp[i][j]);
105         for(int i=1;i<=n;i++)
106             for(int j=i%2+1;j<=m;j+=2)
107                 f[i][j]=false,cnt2++,sum2+=mp[i][j];
108         sum1-=sum2;cnt1=n*m-cnt2;
109         if(cnt1==cnt2)
110         {
111             if(sum1!=sum2)printf("-1\n");
112             else
113             {
114                 LL l=maxx,r=inf,ans=-1;
115                 while(l<=r)
116                 {
117                     LL mid=(l+r)/2;
118                     //if(mid<maxx)l=mid+1;
119                     if(check(mid))r=mid-1,ans=mid;
120                     else l=mid+1;
121                 }
122                 if(ans==-1)printf("-1\n");
123                 else printf("%lld\n",sol(ans));
124             }
125         }
126         else
127         {
128             LL ans=(sum1-sum2)/(cnt1-cnt2);
129             if(ans<maxx || check(ans)==false)printf("-1\n");
130             else printf("%lld\n",sol(ans));
131         }
132     }
133     return 0;
134 }

 

posted @ 2018-03-30 07:47  CHerish_OI  阅读(238)  评论(0编辑  收藏  举报