P3973 [TJOI2015]线性代数

https://www.luogu.com.cn/problem/P3973

欺诈题
挺不错的一道题

大力随机化可以拿到99的高分:评测记录

先来化一波式子

\[D=(A\times B-C)\times A^{T} \\= \sum_{i=1}^n(\sum_{j=1}^na[j]*b[j][i]-c[i])*a[i] \\= \sum_{i=1}^n\sum_{j=1}^na[j]*a[i]*b[j][i]-\sum_{i=1}^n a[i]*c[i] \]

考虑这条式子的意义

如果\(a[i],a[j]\)都为\(1\),那么会失去\(c[i],c[j]\),并获得\(b[i][j],b[j][i]\)

这很容易让我们想到最小割

每个\(b[i][j]\)对应一个点,向\(S\)连一条容量为\(b[i][j]\)的边

对于每个\(c[i]\),向\(T\)连一条容量为\(c[i]\)的边

每个\(b[i][j]\)\(c[i],c[j]\)\(inf\)的边

然后用\(\sum_i \sum_j b[i][j] - maxflow\)即可

code:

#include<bits/stdc++.h>
#define N 1000050
using namespace std;
struct edge {
    int v, nxt, c;
} e[N << 1];
int p[N], eid;
void init() {
    memset(p, -1, sizeof p);
    eid = 0;
}
void insert(int u, int v, int c) {
    e[eid].v = v;
    e[eid].c = c;
    e[eid].nxt = p[u];
    p[u] = eid ++;
}
void add(int u, int v, int c) {
    insert(u, v, c), insert(v, u, 0);
}
const int inf = 1e9;
int S, T, d[N];
queue<int> q;
int bfs() {
    for(int i = 0; i <= T; i ++) d[i] = -1;
    q.push(S), d[S] = 0;
    while(q.size()) {
        int u = q.front(); q.pop();
        for(int i = p[u]; i + 1; i = e[i].nxt) {
            int v = e[i].v, c = e[i].c;
            if(c && d[v] == -1) {
                d[v] = d[u] + 1;
                q.push(v);
            }
        }
    }
    return d[T] != -1; 
}
int dfs(int u, int flow) {
    if(u == T) return flow;
    int ret = 0;
    for(int i = p[u]; i + 1; i = e[i].nxt) {
        int v = e[i].v, c = e[i].c;
        if(c && d[v] == d[u] + 1) {
            int tmp = dfs(v, min(flow, c));
            e[i].c -= tmp, e[i ^ 1].c += tmp;
            flow -= tmp, ret += tmp;
            if(!flow) break;
        }
    }
    if(!ret) d[u] = - 1;
    return ret;
}
int Dinic() {
    int ret = 0;
    for(; bfs() ;) ret += dfs(S, inf);
    return ret;
}
int n;
int id(int i, int j) {
    return (i - 1) * n + j;
}
int main() {
    init();
    scanf("%d", &n);
    S = n * n + n + 1, T = S + 1;
    int ans = 0;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++) {
            int x;
            scanf("%d", &x); ans += x;
            add(S, id(i, j), x);
            add(id(i, j), n * n + i, inf);
            add(id(i, j), n * n + j, inf);
        }
    for(int i = 1; i <= n; i ++) {
        int x;
        scanf("%d", &x);
        add(i + n * n, T, x);
    }
    printf("%d", ans - Dinic());
    return 0;  
}
posted @ 2022-02-16 15:37  lahlah  阅读(50)  评论(0)    收藏  举报