• 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
    ");
    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
    ");
    123                 else printf("%lld
    ",sol(ans));
    124             }
    125         }
    126         else
    127         {
    128             LL ans=(sum1-sum2)/(cnt1-cnt2);
    129             if(ans<maxx || check(ans)==false)printf("-1
    ");
    130             else printf("%lld
    ",sol(ans));
    131         }
    132     }
    133     return 0;
    134 }
  • 相关阅读:
    VUE中tinymce设置字体大小、字体选择(就没有一篇文章能说的清楚的,那么我就说清楚这个问题)
    解决每次git push时需要输入用户名密码的问题
    vue路由,解决同一路由页面多次触发不刷新页面【vue开发】
    函数防抖和节流
    h5页面如何判断是系统Android,ios还是微信等
    react 结合 Promise 和 async await 解决多个异步请求 后统一设置状态问题
    对数组对象递归遍历给子对象添加父对象属性的方法
    React Hooks 使用指南
    webpack配置介绍
    React 实现键盘监听事件
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8674220.html
Copyright © 2020-2023  润新知