• 【BZOJ2756】奇怪的游戏(二分,最小割)


    题意:

    Blinker最近喜欢上一个奇怪的游戏。
    这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻
    的格子,并使这两个数都加上 1。
    现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同
    一个数则输出-1。

    n,m<=40 a[i,j]<=10^9

    思路:假设我们已经询问最终是否都能变成数字D怎么做?

    注意到黑白点染色后每次加的点必定是1黑点1白点

    设黑格子有k1个,和为s1,白格子有k2个,和为s2

    显然k1*d-s1=k2*d-s2

    d=(s1-s2)/(k1-k2)

    当k1<>k2时D可以直接被计算出,用网络流验证即可,注意当D<max(a[i,j])时显然不可能完成

    当k1=k2时注意到每次加必定黑+1,白+1,如果s1<>s2就不可能完成

    又因为此时n*m为偶数,任意的D如果符合要求,任意的D'>D必定符合要求

    因为总个数为偶数时必定可以设计出方案使所有数都+1

    所以可以二分答案,找到最小的能被取到的D,同样用网络流验证

    网络流验证:

    S——>黑点 流量为D-a[i,j]

    白点——>T 流量为D-a[i,j]

    黑点——>相邻的白点 流量为oo

    看最小割是否等于需要被加上的总和即可,因为每个黑点只向相邻的白点连边所以一个最小割就对应了一个操作的方案

    另外二分上界只需要2^50,太大会炸

    num数组一定要动态开,直接设完全部会导致标号不连续调了一天全是泪

      1 const oo=1<<50;
      2       dx:array[1..4]of longint=(-1,1,0,0);
      3       dy:array[1..4]of longint=(0,0,-1,1);
      4 var head,gap,dis:array[0..2000]of longint;
      5     vet,next,fan:array[1..200000]of longint;
      6     len:array[1..200000]of int64;
      7     num,a:array[1..40,1..40]of longint;
      8     n,m,i,j,tot,k1,k2,s,source,src,cas,v,mx:longint;
      9     l,r,mid,last,s1,s2,k:int64;
     10 
     11 procedure add(a,b:longint;c:int64);
     12 begin
     13  inc(tot);
     14  next[tot]:=head[a];
     15  vet[tot]:=b;
     16  len[tot]:=c;
     17  head[a]:=tot;
     18 
     19  inc(tot);
     20  next[tot]:=head[b];
     21  vet[tot]:=a;
     22  len[tot]:=0;
     23  head[b]:=tot;
     24 end;
     25 
     26 function min(x,y:int64):int64;
     27 begin
     28  if x<y then exit(x);
     29  exit(y);
     30 end;
     31 
     32 function dfs(u:longint;aug:int64):int64;
     33 var e,v,val:longint;
     34     flow,t:int64;
     35 begin
     36  if u=src then exit(aug);
     37  e:=head[u]; val:=s-1; flow:=0;
     38  while e<>0 do
     39  begin
     40   v:=vet[e];
     41   if len[e]>0 then
     42   begin
     43    if dis[u]=dis[v]+1 then
     44    begin
     45     t:=dfs(v,min(len[e],aug-flow));
     46     len[e]:=len[e]-t;
     47     len[fan[e]]:=len[fan[e]]+t;
     48     flow:=flow+t;
     49     if dis[source]>=s then exit(flow);
     50     if aug=flow then break;
     51    end;
     52    val:=min(val,dis[v]);
     53   end;
     54   e:=next[e];
     55  end;
     56  if flow=0 then
     57  begin
     58   dec(gap[dis[u]]);
     59   if gap[dis[u]]=0 then dis[source]:=s;
     60   dis[u]:=val+1;
     61   inc(gap[dis[u]]);
     62  end;
     63  exit(flow);
     64 end;
     65 
     66 function maxflow:int64;
     67 var ans:int64;
     68 begin
     69  fillchar(gap,sizeof(gap),0);
     70  fillchar(dis,sizeof(dis),0);
     71  gap[0]:=s; ans:=0;
     72  while dis[source]<s do ans:=ans+dfs(source,oo);
     73  exit(ans);
     74 end;
     75 
     76 function max(x,y:longint):longint;
     77 begin
     78  if x>y then exit(x);
     79  exit(y);
     80 end;
     81 
     82 function isok(k:int64):boolean;
     83 begin
     84  if k*k1-s1=maxflow then exit(true);
     85  exit(false);
     86 end;
     87 
     88 procedure build(k:int64);
     89 var i,j,l,x,y:longint;
     90 begin
     91  fillchar(head,sizeof(head),0); tot:=0;
     92  for i:=1 to n do
     93   for j:=1 to m do
     94    if (i+j) mod 2=0 then
     95    begin
     96     for l:=1 to 4 do
     97     begin
     98      x:=i+dx[l]; y:=j+dy[l];
     99      if (x>0)and(x<=n)and(y>0)and(y<=m) then add(num[i,j],num[x,y],oo);
    100     end;
    101    end;
    102 
    103  for i:=1 to n do
    104   for j:=1 to m do
    105    if (i+j) mod 2=0 then add(source,num[i,j],k-a[i,j])
    106     else add(num[i,j],src,k-a[i,j]);
    107 end;
    108 
    109 begin
    110  assign(input,'bzoj2756.in'); reset(input);
    111  assign(output,'bzoj2756.out'); rewrite(output);
    112  read(cas);
    113  for i:=1 to 200000 do
    114   if i mod 2=1 then fan[i]:=i+1
    115    else fan[i]:=i-1;
    116 // for i:=1 to 40 do
    117  // for j:=1 to 40 do num[i,j]:=(i-1)*40+j;
    118  for v:=1 to cas do
    119  begin
    120   read(n,m);
    121   s1:=0; s2:=0; k1:=0; k2:=0; mx:=-maxlongint;
    122   for i:=1 to n do
    123    for j:=1 to m do
    124    begin
    125     read(a[i,j]);
    126     if (i+j) mod 2=0 then begin inc(k1); s1:=s1+a[i,j]; end
    127      else begin inc(k2); s2:=s2+a[i,j]; end;
    128     mx:=max(mx,a[i,j]); num[i,j]:=(i-1)*m+j;
    129    end;
    130   s:=n*m+2; source:=n*m+1; src:=n*m+2;
    131   if k1<>k2 then
    132   begin
    133    k:=(s1-s2) div (k1-k2);
    134    if k<mx then writeln(-1)
    135     else
    136     begin
    137      build(k);
    138      if isok(k) then writeln(k*k1-s1)
    139       else writeln(-1);
    140     end;
    141   end
    142    else
    143    begin
    144     if s1<>s2 then writeln(-1)
    145      else
    146      begin
    147       l:=mx; r:=oo; last:=oo;
    148       while l<=r do
    149       begin
    150        mid:=(l+r)>>1;
    151        build(mid);
    152        if isok(mid) then begin last:=mid; r:=mid-1; end
    153         else l:=mid+1;
    154       end;
    155       writeln(last*k1-s1);
    156      end;
    157    end;
    158 
    159 
    160  end;
    161 
    162  close(input);
    163  close(output);
    164 end.
  • 相关阅读:
    动态规划之背包问题
    Python中import导入上一级目录模块及循环import问题的解决
    Anaconda介绍、安装及使用教程
    负载均衡基础知识
    TCP和UDP的区别(转)
    microsoft visual c++ 14.0 is required问题解决办法
    python使用requests时报错requests.exceptions.SSLError: HTTPSConnectionPool
    解决Anaconda无法更新的问题
    彻底的理解TCP协议的三次握手和四次分手
    android调试工具 adb命令学习
  • 原文地址:https://www.cnblogs.com/myx12345/p/6227282.html
Copyright © 2020-2023  润新知