jzoj2701 【GDKOI2012模拟02.01】矩阵

传送门:https://jzoj.net/senior/#main/show/2701

【题目大意】

给出矩阵A,求矩阵B,使得

最小,矩阵B每个元素在[L,R]内

n<=200,1<=Aij,L,R<=1000, L<=R

【题解】

我们二分答案x,然后对行列建点,每行向每列连[L,R]的边,然后S向每行连[max(S[i]-x), S[i]+x]的边,每列向T连[max(T[i]-x), T[i]+x]的边,判断是否有可行流即可。

其中S[i]表示A中第i行的和,T[i]表示A中第i列的和。

判断有源汇上下界可行流:按照无源汇那样建边,多来一条(T->S,[0,inf])即可。

然后跑dinic,判断从SS流出的边是否全流满。

# include <queue>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 200 + 10, N = 5e5 + 10, inf = 1e9;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, m, a[M][M], s1[M], s2[M], S, T, L, R;
int head[M * 4], nxt[N], to[N], flow[N], tot, indeg[M * 4];
inline void add(int u, int v, int fl) {
    ++tot; nxt[tot] = head[u]; head[u] = tot;
    to[tot] = v; flow[tot] = fl;
}
inline void adde(int u, int v, int fl) {
    add(u, v, fl), add(v, u, 0);
}

inline void tadd(int u, int v, int lf, int rf) {
    adde(u, v, rf-lf);
    indeg[v] += lf;
    indeg[u] -= lf;
}

namespace MF {
    queue<int> q;

    int c[M * 3], cur[M * 3];
    inline bool bfs() {
        for (int i=1; i<=n+m+4; ++i) c[i] = -1;
        while(!q.empty()) q.pop();
        q.push(S); c[S] = 1;
        while(!q.empty()) {
            int top = q.front(); q.pop();
            for (int i=head[top]; i; i=nxt[i]) {
                if(c[to[i]] != -1 || flow[i] == 0) continue;
                c[to[i]] = c[top] + 1;
                q.push(to[i]);
                if(to[i] == T) return 1;
            }
        }
        return 0;
    }

    inline int dfs(int x, int low) {
        if(x == T) return low;
        int r = low, fl;
        for (int i=cur[x]; i; i=nxt[i]) {
            if(c[to[i]] != c[x]+1 || flow[i] == 0) continue;
            fl = dfs(to[i], min(r, flow[i]));
            flow[i] -= fl; flow[i^1] += fl; r -= fl;
            if(flow[i] > 0) cur[x] = i;
            if(!r) return low;
        }
        if(r == low) c[x] = -1;
        return low-r;
    }

    inline int main() {
        int ans = 0;
        while(bfs()) {
            for (int i=1; i<=n+m+4; ++i) cur[i] = head[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
}

# define line(x) (x)
# define row(x) (x+n) 

inline void build(int x) {
    int SS = n+m+1, TT = n+m+2;
    S = n+m+3, T = n+m+4;
    for (int i=1; i<=n+m+2; ++i) indeg[i] = 0;
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=m; ++j)
            tadd(line(i), row(j), L, R);
    for (int i=1; i<=n; ++i)
        tadd(SS, line(i), max(0, s1[i]-x), s1[i]+x);
    for (int i=1; i<=m; ++i)
        tadd(row(i), TT, max(0, s2[i]-x), s2[i]+x);
    tadd(TT, SS, 0, inf);
    for (int i=1; i<=n+m+2; ++i) {
        if(indeg[i] < 0) adde(i, T, -indeg[i]);
        else adde(S, i, indeg[i]);
    }
}

inline bool chk(int x) {
    tot = 1; memset(head, 0, sizeof head);
    build(x);
    MF::main();
//    cout << x << endl;
    for (int i=head[S]; i; i=nxt[i]) {
//        cout << flow[i] << ‘ ‘;
        if(flow[i] != 0) {
//            cout << endl;
            return false;
        }
    }
//    cout << endl;
    return true;
}

inline void gans(int ans) {
    for (int i=1; i<=n; ++i, puts("")) {
        for (int j=1; j<=m; ++j) {
            for (int p=head[line(i)]; p; p=nxt[p]) {
                if(to[p] == row(j)) {
                    printf("%d ", flow[p^1] + L);
                    break;
                }
            }
        }
    }
}

int main() {
    freopen("mat.in", "r", stdin);
    freopen("mat.out", "w", stdout);
    cin >> n >> m;
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=m; ++j) {
            scanf("%d", &a[i][j]);
            s1[i] += a[i][j];
            s2[j] += a[i][j];
        }
    cin >> L >> R;
    int l = 0, r = 2e5, mid, ans = 0;
    while(1) {
        if(r-l <= 3) {
            for (int i=l; i<=r; ++i)
                if(chk(i)) {
                    ans = i;
                    break;
                }
            break;
        }
        mid = l+r>>1;
        if(chk(mid)) r = mid;
        else l = mid;
    }
    cout << ans << endl;
    gans(ans);
    return 0;
}

时间: 2024-10-28 23:03:22

jzoj2701 【GDKOI2012模拟02.01】矩阵的相关文章

jzoj2700 【GDKOI2012模拟02.01】数字

传送门:https://jzoj.net/senior/#main/show/2700 [题目大意] 令n为正整数,S(n)为n的各位数字之和,令 小Z喜欢的数一定能表示成 x * D(x) 这种形式. 小D也是个开朗的人,他知道QQ号码是随出来的.那么,他想知道在区间[L, R]中,他喜欢的数出现了多少次呢? 多组数据. 1<=T<=5, 1<=L<=R<=10^18 [题解] 打一个表就知道D(n)=((n-1) mod 9) + 1 然后我们如果有k * D(k) =

ACDream 1213 Matrix Multiplication (01矩阵处理)

Matrix Multiplication Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description Let us consider undirected graph G = {V; E} which has N vertices and M edges. Incidence matrix of

关于codehunt Level 02.01 的疑问

codehunt Level 02.01 原题大意如下 : 假设给定下列函数声明 public static int[] Puzzle(int n) { return null; } 要求写出该方法具体函数代码,返回值应为下列类似的值 n 值 1 {0} 2 {0, 1} 3 {0, 1, 2} 我写的如下方法 public static int[] Puzzle(int n) { int[] re = new int[n]; for (int i=0; i<n; i++) re[i] = i;

HNU 10111 0-1矩阵

http://acm.hnu.cn/online/?action=problem&type=show&id=10111 题意:中文 题解:在龙哥的帮助下正了二分图匹配的三观--以前的理解繁琐,或者有点儿错吧--二分图匹配从左往右匹配,找增广路.顶点数和match()不需要那么麻烦. 1 // 2 // main.cpp 3 // POJ 3041 4 // 5 // Created by zhang on 14-4-16. 6 // Copyright (c) 2014年 apple. A

统计01矩阵中全1子矩阵的个数

统计01矩阵中全1子矩阵的个数 1.51Nod 1291 题意:600*600的01矩阵,统计宽i高j的全1矩阵的个数. 题解:枚举矩阵的下边界,对于每个下边界,统计所有宽极大的矩形的答案(高度可以用差分).\(n^2\) 统计完之后,我们已知所有高度的宽极大的答案,列一下式子发现两次前缀和就是最后答案. 代码: #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define mp

[EOJ Monthly 2018.10][C. 痛苦的 01 矩阵]

题目链接:C. 痛苦的 01 矩阵 题目大意:原题说的很清楚了,不需要简化_(:з」∠)_ 题解:设\(r_i\)为第\(i\)行中0的个数,\(c_j\)为第\(j\)列中0的个数,\(f_{i,j}\)代表对应格子是否为0,则有\(cost(i,j)=r_i+c_j-f_{i,j}\),\((cost(i,j))^2=r_i^2+c_j^2+f_{i,j}+2r_ic_j-2f_{i,j}(r_i+c_j)\) $$\sum_{i=1}^n \sum_{j=1}^n \left( cost(

Leetcode 542.01矩阵

01矩阵 给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离. 两个相邻元素间的距离为 1 . 示例 1: 输入: 0 0 0 0 1 0 0 0 0 输出: 0 0 0 0 1 0 0 0 0 示例 2: 输入: 0 0 0 0 1 0 1 1 1 输出: 0 0 0 0 1 0 1 2 1 注意: 给定矩阵的元素个数不超过 10000. 给定矩阵中至少有一个元素是 0. 矩阵中的元素只在四个方向上相邻: 上.下.左.右. 思路 先把所有0入队,把1置为MAX_VALUE,然

02.02.01 第1章 简介及基础操作(Power BI商业智能分析)

02.02.01.01 powerbi简介 00:10:59 02.02.01.02 query数据导入 00:03:26 具体操作实例如下: 02.02.01.03导入access数据 00:05:40 方式一:加载 方式二:加载 到 双击用户明细,进入Power Query 02.02.01.04导入csv和Excel和txt文件 00:04:47 02.02.01.05纵向合并数据 00:03:14 02.02.01.06横向合并数据 00:05:11 02.02.01.07数据填充 00

Leetcode 542:01 矩阵 01

Leetcode 542:01 矩阵 01 Matrix### 题目: 给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离. 两个相邻元素间的距离为 1 . Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell. The distance between two adjacent cells is 1. 示例 1: 输入: 0 0 0 0 1 0 0 0 0 输出