zoukankan      html  css  js  c++  java
  • bzoj 2756

    传送门http://www.lydsy.com/JudgeOnline/problem.php?id=2756

    基本思路:我们考虑可以变成的最终的状态,假设每一位置的数都是x, 由于对于相连的格子一起加1, 那么我们就可以对方格进行黑白染色(相邻格子的颜色严格不同),假设个数分别为c1, c2, 总和为s1, s2, 那么 c1 * x - s1 = c2 * x - s2, x = (s1 - s2) / (c1 - c2); 当n * m % 2 == 1 时 c1 != c2, 可以反解x; 否则x在某一个值以上的时候一定都可以满足,就可以二分了。

    重点就是如何检验x是否可行,然后方法是对于黑格子向原点连x - a[i][j] 的边,然后白格子向汇点连x - a[i][j]的边, 然后相邻的格子连inf的边,跑满流就可以了。

    warning: 首先我们需要两个inf 分别表示流量的最大值和二分最大值,不能一样,然后二分的最小边界必须是a[i][j] 中的最大值减1,因为要保证x > Max{a[i][j]}

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long qword;
    
    const qword maxl = 50;
    const qword maxn = maxl * maxl;
    const qword dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    const qword inf = 0x3f3f3f3f;
    const qword infll = (1ll << 60);
    
    qword n, m, sum[2], c[2];
    qword a[maxl][maxl], col[maxl][maxl];
    
    struct edge {
        qword t, c;
        edge* next, *other;
    }e[maxn * 10]; qword ne = 0; edge* head[maxn];
    
    void addedge(qword f, qword t, qword c) {
        e[ne].t = t, e[ne].c = c, e[ne].next = head[f], head[f] = e + ne ++;
        e[ne].t = f, e[ne].c = 0, e[ne].next = head[t], head[t] = e + ne ++;
        e[ne - 1].other = e + ne - 2;
        e[ne - 2].other = e + ne - 1;
    }
    
    qword q[maxn], l, r; qword dis[maxn];
    qword s, t;
    
    bool bfs() {
        memset(dis, 0, sizeof(dis));
        dis[s] = 1;
        l = r = 0; q[r ++] = s;
        while(l ^ r) {
            qword x = q[l ++];
            for(edge* p = head[x]; p; p = p-> next) {
                if(!dis[p-> t] && p-> c) {
                    q[r ++] = p-> t; dis[p-> t] = dis[x] + 1;
                }
            }
        }
        return (bool)dis[t];
    }
    
    /*qword dfs(qword x, qword flow) {
        if(x == t) return flow;
        if(!flow) return 0;
        qword ret = 0, maxflow;
        for(edge* p = head[x]; p && flow; p = p-> next) {
            if(p-> c && dis[p-> t] == dis[x] + 1 && (maxflow = dfs(p-> t, min(flow, p-> c)))) {
                p-> c -= maxflow, p-> other-> c += maxflow;
                ret += maxflow, flow -= maxflow;
            }
        }
        return ret;
    }*/
    
    edge* Next[maxn]; qword sta[maxn], top = 0;
    
    qword dfs() {
        for(qword i = s; i <= t; ++ i) Next[i] = head[i];
        top = 0;
        sta[++ top] = s; 
        qword ret = 0;
        while(top) {
            qword x = sta[top];
            if(x == t) {
                qword minfl = infll + 1000;
                qword last;
                for(qword i = 1; i < top; ++ i) {
                    if(Next[sta[i]]-> c < minfl) 
                        minfl = Next[sta[i]]-> c, last = i;
                }
                for(qword i = 1; i < top; ++ i) {
                    edge* p = Next[sta[i]];
                    p-> c -= minfl, p-> other-> c += minfl;
                }
                ret += minfl, top = last;
                continue;
            }
            edge* px;
            for(px = Next[x]; px; px = px-> next) {
                if(dis[px-> t] == dis[x] + 1 && px-> c) {
                    sta[++ top] = px-> t; break;
                }
            }
            Next[x] = px;
            if(Next[x] == NULL) {
                top --;
                if(Next[sta[top]]) Next[sta[top]] = Next[sta[top]]-> next;
            }
        }
        return ret;
    }
    
    qword get(qword x, qword y) {
        return (x - 1) * m + y;
    }
    
    bool flow(qword x) {
        ne = 0;
        memset(head, 0, sizeof(head));
        qword tl = 0;
        for(qword i = 1; i <= n; ++ i) {
            for(qword j = 1; j <= m; ++ j) {
                qword tmp = x - a[i][j];
                if(col[i][j] == 0) addedge(0, get(i, j), tmp);
                else addedge(get(i, j), t, tmp);
                tl += tmp;
            }
        }
        for(qword i = 1; i <= n; ++ i) {
            for(qword j = 1; j <= m; ++ j) {
                if(col[i][j] == 0) {
                    for(qword l = 0; l < 4; ++ l) {
                        qword x = i + dir[l][0];
                        qword y = j + dir[l][1];
                        if(x < 1 || x > n || y < 1 || y > m) continue;
                        addedge(get(i, j), get(x, y), infll);
                    }
                }
            }
        }
        qword fl = 0;
        while(bfs()) fl += dfs();
        return (tl == fl * 2);
    }
    
    qword getans(qword x) {
        return ((n * m * x - sum[0] - sum[1]) >> 1);
    }
    
    void sov() {
        qword T; scanf("%lld", &T);
        qword Max = 0;
        while(T --) {
            Max = 0;
            scanf("%lld%lld", &n, &m);
            memset(sum, 0, sizeof(sum)); 
            memset(c, 0, sizeof(c));
            col[0][1] = 1;
            for(qword i = 1; i <= n; ++ i) {
                qword cl = !col[i - 1][1];
                for(qword j = 1; j <= m; ++ j) {
                    scanf("%lld", &a[i][j]);
                    col[i][j] = cl; cl = !cl;
                    c[col[i][j]] ++, sum[col[i][j]] += a[i][j];
                    Max = max(Max, a[i][j]);
                }
            }
            s = 0, t = n * m + 1;
            if(n * m % 2) {
                qword x = abs(sum[0] - sum[1]);
                if(x >= Max && flow(x)) printf("%lld
    ", getans(x));
                else printf("-1
    ");
            }
            else {
                qword ls = Max - 1, rs = inf * 1000;
                qword ans = -1;
                while(rs - ls > 1) { 
                    qword mid = (ls + rs) >> 1;
                    if(flow(mid)) rs = mid, ans = mid;
                    else ls = mid;
                }
                if(ans == -1) printf("-1
    ");
                else printf("%lld
    ", getans(ans));
            }
        }
    }
    
    int main() {
        //freopen("test.in", "r", stdin);
        //freopen("test.out", "w", stdout);
        sov();
        return 0;
    }
  • 相关阅读:
    bzoj 2763: [JLOI2011]飞行路线
    2008年NOI全国竞赛 假面舞会
    八数码(双向宽搜)
    poj 1988 Cube Stacking && codevs 1540 银河英雄传说(加权并茶几)
    codevs 3693 数三角形
    bzoj 3831 Little Bird (单调队列优化dp)
    hdu 3530 Subsequence
    poj 2823 Sliding Window(单调队列)
    线段树各种小练习
    codevs 2449 骑士精神 (IDDfs)
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/4147310.html
Copyright © 2011-2022 走看看