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

    题目链接:戳我

    怎么说呢,看到棋盘(应该想到二分图染色)

    设白色格子数量为(cnt0),现在的值的和为(sum0)。黑色格子的数量为(cnt1),现在的值的和为(sum1),最后的答案为x。

    (sum0+cnt0*x=sum1+cnt1*x)
    (sum0-sum1=x*(cnt1-cnt0))

    如果(cnt1-cnt0)不为0的时候,我们可以直接获得答案,然后验证答案的正确性。

    我们不容易知道到底最后的终止数为多少,但是我们知道如果格子数量是偶数的话,如果一个x成立,那么比它大的数一定也成立,但是比它小的数就不一定成立了。所以可!以!二!分!,然后把这个题转化成一个判定性问题。但是最后也别忘了验证答案的正确性。(二分的范围取$[l,l+0x3f3f3f3f]就行了)

    怎么验证答案的正确性呢?不就是是否存在一个方案使得按照题目的意思进行操作,所有的数都能达到x吗。

    我们既然黑白染色了,所以就可以将整个棋盘转化成一张二分图。

    如果还需要增加多少,就向S或者T连容量为多少的边。然后相邻的格子连INF。

    最后注意因为这个数比较大,所以要开long long!!!

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<ctime>
    #define S 0
    #define T n*m+1
    #define MAXN 2010
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    int n,m,t=1,tt;
    int a[45][45];
    int head[MAXN],dep[MAXN],cur[MAXN],dis[MAXN];
    int move_x[4]={1,-1,0,0},move_y[4]={0,0,1,-1};
    struct Edge{int nxt,to;long long dis;}edge[2000010];
    inline void add(int from,int to,long long dis)
    {
        edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;
        edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=0,head[to]=t;
    }
    inline bool bfs()
    {
        memset(dep,0x3f,sizeof(dep));
        memcpy(cur,head,sizeof(head));
        queue<int>q;
        q.push(S);
        dep[S]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if(dep[v]==0x3f3f3f3f&&edge[i].dis)
                {
                    dep[v]=dep[u]+1;
                    q.push(v);
                }
            }
        }
        if(dep[T]==0x3f3f3f3f) return false;
        return true;
    }
    inline long long dfs(int x,long long f)
    {
        if(x==T||!f) return f;
        long long used=0,w;
        for(int i=cur[x];i;i=edge[i].nxt)
        {
            cur[x]=i;
            if(dep[edge[i].to]==dep[x]+1&&(w=dfs(edge[i].to,min(f,edge[i].dis))))
            {
                used+=w,f-=w;
                edge[i].dis-=w,edge[i^1].dis+=w;
                if(!f) break;
            }
        }
        return used;
    }
    inline long long dinic()
    {
        long long cur_ans=0;
        while(bfs()) cur_ans+=dfs(S,INF);
        return cur_ans;
    }
    inline int id(int x,int y){return (x-1)*m+y;}
    inline bool check(long long x)
    {
        long long all=0;
        memset(head,0,sizeof(head));
        t=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                if((i+j)&1) 
                {
                    add(S,id(i,j),x-a[i][j]);
                    for(int k=0;k<=3;k++)
                    {
                        int xx=i+move_x[k];
                        int yy=j+move_y[k];
                        if(xx<1||xx>n||yy<1||yy>m) continue;
                        add(id(i,j),id(xx,yy),INF);
                    }
                    all+=x-a[i][j];
                }
                else add(id(i,j),T,x-a[i][j]);
            }
        long long cur_ans=dinic();
        if(cur_ans!=all) return false;
        return true;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d",&tt);
        while(tt--)
        {
            memset(head,0,sizeof(head));
            t=1;
            long long tot=0;
            scanf("%d%d",&n,&m);
            long long l=0,r=l+INF;
            long long sum0=0,sum1=0,cnt0=0,cnt1=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    scanf("%d",&a[i][j]),l=max(l,1ll*a[i][j]);
                    tot+=a[i][j];
                    if((i+j)&1) cnt0++,sum0+=a[i][j];
                    else cnt1++,sum1+=a[i][j];
                }
            if(cnt0!=cnt1)
            {
                long long ans=(sum0-sum1)/(cnt0-cnt1);
                if(check(ans)==true&&1ll*ans>=l) printf("%lld
    ",(1ll*ans*n*m-tot)/2);
                else printf("-1
    ");
            }
            else
            {
                if(sum0!=sum1) {printf("-1
    ");continue;}
                long long ans=-1;
                while(l<=r)
                {
                    long long mid=(l+r)>>1;
                    if(check(mid)) ans=mid,r=mid-1;
                    else l=mid+1;
                }
                if(ans==-1) printf("-1
    ");
                else printf("%lld
    ",(1ll*ans*n*m-tot)/2);
            }
        }
        
        return 0;
    }
    
  • 相关阅读:
    CVSps 3.8 发布,CVS 资料库更改收集
    Cobra WinLDTP 3.0 发布,GUI 自动化测试
    SolusOS 2 Alpha 6 发布,桌面 Linux 发行
    微软 Windows Phone 8 原创应用大赛起航
    JAVA削足适履适应RESTful设计
    如何撰写编程书籍
    Synbak 2.1 发布,系统备份工具
    LibreOffice 4.0 RC1 发布,支持火狐兼容主题
    Rails 3.2.11 发布,修复关键安全问题
    haveged 1.7 发布,随机数生成器
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10888373.html
Copyright © 2011-2022 走看看