bzoj4514 digital pairing

thinking

Think of the cost stream first.
Split points for each point. Then consider how we can ensure that each point is used only once.
If \ (i \) and \ (j \) meet the conditions. Then connect an edge from \ (i \) to \ (j \) and from \ (j \) to \ (i \). In this way, every time we expand, we can see that a certain edge has been expanded twice. Obviously, the edges from \ (i \) to \ (j \) and from \ (j \) to \ (i \) are equivalent. That is to say, if the edge between the two points of current augmentation is better, then the other edges will not be expanded until the traffic of the two sides from \ (i \) to \ (j \) and from \ (j \) to \ (i \) becomes \ (0 \).
It's hard to explain. If you think about it carefully, it's right. In the end, we find that the traffic is actually twice the answer. Divide by two.
Then we should consider the limitation of value in the topic. We regard value as the cost, and the path to maximize the cost each time. Until the cost of further expansion becomes negative.

Code

/*
* @Author: wxyww
* @Date:   2019-02-17 14:52:25
* @Last Modified time: 2019-02-17 19:36:45
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 410,M = 1000000 + 100,INF = 1e9;
ll read() {
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
struct node {
    int v,nxt,w;
    ll cost;
}e[M];
int head[N],ejs = 1;
void add(int u,int v,int w,ll c) {
    e[++ejs].v = v;e[ejs].w = w;e[ejs].cost = c;e[ejs].nxt = head[u];head[u] = ejs;
    e[++ejs].v = u;e[ejs].w = 0;e[ejs].cost = -c;e[ejs].nxt = head[v];head[v] = ejs;
}
int a[N],vis[N],fa[N],b[N];
ll dis[N],c[N];
queue<int>q;
int S,T;
bool pd(int x,int y) {
    if(x < y) swap(x,y);
    if(!y || x == y) return false;
    if(x % y) return false;
    int k = x/y;
    for(int i = 2;i * i <= k;++i)
        if(k % i == 0) return false;
    return true;
}
bool spfa() {
    while(!q.empty()) q.pop();
    memset(dis,-0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(fa,0,sizeof(fa));
    q.push(S);dis[S] = 0;
    while(!q.empty()) {
        int u = q.front();q.pop();vis[u] = 0;
        for(int i = head[u];i;i = e[i].nxt) {
            int v = e[i].v;
            if(dis[v] < dis[u] + e[i].cost && e[i].w) {
                dis[v] = dis[u] + e[i].cost;
                fa[v] = i;
                if(!vis[v]) q.push(v),vis[v] = 1;
            }
        }
    }
    return fa[T];
}
ll dinic() {
    ll COST = 0,FLOW = 0;
    while(spfa()) {
        int mn = INF;
        for(int i = fa[T];i;i = fa[e[i ^ 1].v]) mn = min(mn,e[i].w);
        for(int i = fa[T];i;i = fa[e[i ^ 1].v]) e[i].w -= mn,e[i ^ 1].w += mn;
        if(COST + dis[T] * mn < 0) {
            FLOW += COST / -dis[T];
            return FLOW;
        }
        COST += dis[T] * mn;
        FLOW += mn;
    }
    return FLOW;
}
int main() {
    int n = read();
    for(int i = 1;i <= n;++i) a[i] = read();
    for(int i = 1;i <= n;++i) b[i] = read();
    for(int i = 1;i <= n;++i) c[i] = read();
    S = n * 2 + 1,T = S + 1;
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= n;++j)
            if(i != j && pd(a[j],a[i]))
                add(i,j + n,INF,c[i] * c[j]);
    int tot = ejs;
    for(int i = 1;i <= n;++i) add(S,i,b[i],0);
    for(int i = 1;i <= n;++i) add(i + n,T,b[i],0);
    cout<<(dinic() >> 1);
    return 0;
}

Keywords: C++

Added by Bigun on Tue, 03 Dec 2019 22:45:44 +0200