【LOJ】#2031. 「SDOI2016」数字配对

题解

这个图是个二分图,因为如果有一个奇环的话,我们会发现一个数变成另一个数要乘上个数不同的质数,显然不可能

然后我们发现这个不是求最大流,而是问一定价值的情况下最大流是多少,二分一个流量,加上一条边限流,然后求最小费用(其实是最大费用,把权值取反即可)是不是小于等于0,再看流量有没有流满

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
//#define ivorysi
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define mo 974711
#define MAXN 15005
#define RG register
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {putchar('-');x = -x;}
    if(x >= 10) {
        out(x / 10);
    }
    putchar('0' + x % 10);
}
int N;
int a[405],b[405],col[405];
int64 c[405],g[405][405];
bool vis[405],E[405][405];
int totflow;
int64 totval,pi1;
struct node {
    int to,next,cap;
    int64 val;
}Edge[500005];
int head[407],sumE,S,T;
void add(int u,int v,int c,int64 a) {
    Edge[++sumE].to = v;Edge[sumE].next = head[u];
    Edge[sumE].cap = c;Edge[sumE].val = a;
    head[u] = sumE;
}
void addtwo(int u,int v,int c,int64 a) {
    add(u,v,c,a);add(v,u,0,-a);
}
bool check(int x) {
    if(x == 1) return false;
    for(int i = 2 ; i <= x / i ; ++i) {
        if(x % i == 0) return false;
    }
    return true;
}
void dfs(int u,int id) {
    vis[u] = 1;
    col[u] = id;
    for(int v = 1 ; v <= N ; ++v) {
        int s = a[u],t = a[v];
        if(s < t) swap(s,t);
        if(s % t == 0 && check(s / t)) {
            g[u][v] = g[v][u] = -c[u] * c[v];
            E[u][v] = E[v][u] = 1;
            if(!vis[v]) dfs(v,id ^ 1);
        }
    }
}
int aug(int u,int C) {
    if(u == T) {
        totflow += C;
        totval += pi1 * C;
        return C;
    }
    int flow = 0;
    vis[u] = 1;
    for(int i = head[u] ; i ; i = Edge[i].next) {
        int v = Edge[i].to;
        if(Edge[i].cap && !vis[v] && Edge[i].val == 0) {
            int t = aug(v,min(C - flow,Edge[i].cap));
            flow += t;
            Edge[i].cap -= t;
            Edge[i ^ 1].cap += t;
            if(flow == C) return flow;
        }
    }
    return flow;
}
bool modlabel() {
    int64 d = 1e18;
    for(int i = 1 ; i <= T ; ++i) {
        if(vis[i]) {
            for(int j = head[i] ; j ; j = Edge[j].next) {
                int v = Edge[j].to;
                if(Edge[j].cap && !vis[v] && Edge[j].val < d) 
                    d = Edge[j].val;
            }
        }
    }
    if(d == 1e18) return false;
    pi1 += d;
    for(int i = 1 ; i <= T ; ++i) {
        if(vis[i]) {
            for(int j = head[i] ; j ; j = Edge[j].next) {
                Edge[j].val -= d;
                Edge[j ^ 1].val += d;
            }
        }
    }
    return true;
}
bool check_flow(int MID) {
    memset(head,0,sizeof(head));sumE = 1;
    totval = 0;totflow = 0;pi1 = 0;
    for(int i = 1 ; i <= N ; ++i) {
        if(!col[i]) addtwo(N + 1,i,b[i],0);
        else addtwo(i,T,b[i],0);
    }
    for(int i = 1 ; i <= N ; ++i) {
        if(!col[i]) {
            for(int j = 1 ; j <= N ; ++j) {
                if(col[j] && E[i][j]) {
                    addtwo(i,j,0x7fffffff,g[i][j]);
                } 
            }
        }
    }
    addtwo(S,N + 1,MID,0);
    do {
        do{
            memset(vis,0,sizeof(vis));
        }while(aug(S,0x7fffffff));
    }while(modlabel());
    return totflow >= MID && totval <= 0;
}
void Init() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) read(a[i]);
    for(int i = 1 ; i <= N ; ++i) read(b[i]);
    for(int i = 1 ; i <= N ; ++i) read(c[i]);
    for(int i = 1 ; i <= N ; ++i)
        if(!vis[i]) dfs(i,0);
    S = N + 2;T = N + 3;
}
void Solve() {
    int L = 0,R = 0;
    for(int i = 1 ; i <= N ; ++i) R += b[i];
    R /= 2;
    while(L < R) {
        int mid = (L + R + 1) >> 1;
        if(check_flow(mid)) L = mid;
        else R = mid - 1;
    }
    out(L);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ivorysi/p/9120327.html
今日推荐