有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,
那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。


这道题如果取消那个总和不小于0的情况呢?
然后我们发现可以用最大流做,就是把a[i]有奇数个质因子的连向源点,偶数个质因子连向汇点
建边,跑个最大流就可以了,正确性?显然啊
现在把总和不小于0的情况考虑进来,我们发现有费用了
我们考虑跑最大费用最大流,那么由于每次增广的是一个较大的费用
也就是说每次增广出来的费用是递减的
这样我们就可以当cost<0时,输出答案
这样有一个问题,就是说最后一次增广出来的流量是不能全部跑出来的,也许会跑出来一部分
那么这一部分可以通过cost / -dis[t]这种方式求出来,于是问题完美的解决啦

#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
#define llinf 2000000000000000000
#define inf 2147483647
#define for1(i, x, y) for(LL i = (x); i <= (y); i ++)
#define for2(i, x, y) for(LL i = (x); i >= (y); i --)

namespace mcmf{
    LL s, t;
    struct Edge{
       LL u, v, cap, flow;
       LL cost;
       LL next;
    } G[250010];
    LL tot;
    LL head[3000];
    LL inq[3000];
    LL d[3000];
    LL p[3000];
    LL a[3000];
    inline void init(){
        memset(head, -1, sizeof(head));
        tot = -1;
    }
    inline void add(LL u, LL v, LL w, LL cost){
        G[++ tot] = (Edge){u, v, w, 0, cost, head[u]};
        head[u] = tot;
        G[++ tot] = (Edge){v, u, 0, 0, -cost, head[v]};
        head[v] = tot;
        return;
    }
    inline bool BellmanFord(LL& flow, LL& cost){
        for(LL i = s; i <= t; i ++) d[i] = -llinf;
        memset(inq, 0, sizeof(inq));
        d[s] = 0;
        inq[s] = 1;
        p[s] = 0;
        a[s] = inf;
        queue<LL> Q;
        Q.push(s);
        while(!Q.empty()){
            LL u = Q.front(); Q.pop();
            inq[u] = 0;
            for(LL i = head[u]; i != -1; i = G[i].next){
                Edge& e = G[i];
                if(e.cap > e.flow && d[e.v] < d[u] + e.cost){
                    d[e.v] = d[u] + e.cost;
                    p[e.v] = i;
                    a[e.v] = min(a[u], e.cap - e.flow);
                    if(!inq[e.v]){
                        Q.push(e.v);
                        inq[e.v] = 1;
                    }
                }
            }
        }
        if(d[t] == -llinf) return false;
        flow += a[t];
        cost += d[t] * (LL)a[t];
        if(cost < 0){
            cost -= d[t] * (LL)a[t];
            flow -= a[t];
            flow += cost / -d[t];
            return false;
        }
        LL u = t;
        while(u != s){
            G[p[u]].flow += a[t];
            G[p[u] ^ 1].flow -= a[t];
            u = G[p[u]].u;
        }
        return true;
    }
    inline LL Minflow(){
        LL flow = 0; LL cost = 0;
        while(BellmanFord(flow, cost));
        return flow;
    }
}

LL a[100010], b[100010], c[100010];
LL prime[100010], tot; bool vis[100010];
LL cnta[100010];

inline LL read(){ // getchar较快于scanf,更快的还有fread,不会23333
    char ch = getchar(); LL x = 0, f = 1;
    while(ch < '0' || ch > '9'){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while('0' <= ch && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
} 

inline LL llread(){
    char ch = getchar(); LL x = 0, f = 1;
    while(ch < '0' || ch > '9'){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while('0' <= ch && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
} 

inline void init_prime(){
    for1(i, 2, 100000){
        if(!vis[i]) prime[++ tot] = i;
        for1(j, 1, tot){
            if(i * prime[j] > 100000) break;
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}

inline bool is_prime(LL x){
    if(x <= 100000) return 1 - vis[x];
    LL t = sqrt(x);
    for1(i, 1, tot){
        if(prime[i] > t) break;
        if(x % prime[i] == 0) return false;
    }
    return true;
}

int main(){
    LL n = read();
    for1(i, 1, n) a[i] = llread();
    for1(i, 1, n) b[i] = llread();
    for1(i, 1, n) c[i] = llread();
    mcmf::init();
    init_prime();
    for1(i, 1, n){
        LL t = sqrt(a[i]);
        LL o = a[i];
        for1(j, 1, tot){
            if(prime[j] > t) break;
            while(o % prime[j] == 0) o /= prime[j], cnta[i] ++;
            if(o == 1) break;
        }
        if(o != 1) cnta[i] ++;
    }
    mcmf::s = 0; mcmf::t = n + 1;
    for1(i, 1, n){
        if(cnta[i] & 1) mcmf::add(0, i, b[i], 0);
        else mcmf::add(i, n + 1, b[i], 0);
    }
    for1(i, 1, n) if(cnta[i] & 1){
        for1(j, 1, n) if(!(cnta[j] & 1)){
            if(a[i] % a[j] != 0 && a[j] % a[i] != 0) continue;
            if(a[i] % a[j] == 0 && is_prime(a[i] / a[j])) mcmf::add(i, j, inf, c[i] * c[j]);
            else if(a[j] % a[i] == 0 && is_prime(a[j] / a[i])) mcmf::add(i, j, inf, c[i] * c[j]); 

        }
    }
    printf("%lld", mcmf::Minflow());
    return 0;
}


BZOJ4514——[Sdoi2016]数字配对的更多相关文章

  1. bzoj4514 [Sdoi2016]数字配对

    Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...

  2. BZOJ4514[Sdoi2016]数字配对——最大费用最大流

    题目描述 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci ...

  3. bzoj4514 [Sdoi2016]数字配对(网络流)

    Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...

  4. [bzoj4514][SDOI2016]数字配对——二分图

    题目描述 传送门 题解: 这个题真的是巨坑,经过了6个WA,2个TLE,1个RE后才终于搞出来,中间都有点放弃希望了... 主要是一定要注意longlong! 下面开始说明题解. 朴素的想法是: 如果 ...

  5. BZOJ4514 [Sdoi2016]数字配对 【费用流】

    题目 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×c ...

  6. bzoj4514: [Sdoi2016]数字配对--费用流

    看了一眼题目&数据范围,觉得应该是带下界的费用流 原来想拆点变成二分图,能配对的连边,跑二分图,可行性未知 后来看到另外一种解法.. 符合匹配要求的数要满足:质因子的个数相差为1,且两者可整除 ...

  7. bzoj4514: [Sdoi2016]数字配对(费用流)

    传送门 ps:费用流增广的时候费用和流量打反了……调了一个多小时 每个数只能参与一次配对,那么这就是一个匹配嘛 我们先把每个数分解质因数,记质因子总个数为$cnt_i$,那如果$a_i/a_j$是质数 ...

  8. 【bzoj4514】: [Sdoi2016]数字配对 图论-费用流

    [bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后 ...

  9. 【BZOJ4514】[Sdoi2016]数字配对 费用流

    [BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ...

随机推荐

  1. Javascript setTimeout 带参数延迟执行 闭包实现

    不是原创,只是 借鉴别人的成果,我在此纪念 1.htm function GetDateT() { var d,s; d = new Date(); s = d.getFullYear() + &qu ...

  2. 《Struts2.x权威指南》学习笔记2

    在学习了第二章后,我想要将struts分类,修改一下struts.xml的默认读取路径如下图. 在IntelliJ中,resources是struts的默认路径 修改路径,需要在web.xml中添加s ...

  3. php适配器设计模式

    <?php //适配器模式 //服务器端代码 class tianqi{ public static function show(){ $today= array('tep' =>28 , ...

  4. Sublime Text3快捷键汇总

    选择类 Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本. Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数 ...

  5. mysql中文坑爹的东西

    1.首先pb需要utf8格式,所以由ansi转换成utf8格式才能传输 2.在接收端,需要将utf8转换成ansi才能用 3.在插入数据库之前需要将sql从ansi转换成utf8格式 4.数据库设置字 ...

  6. Linux的95个小技巧

    Linux的95个小技巧 by WEB全栈工程师 on 2012 年 03 月 27 日 这里总结了Linux使用中的一些小技巧 1.实现RedHat非正常关机的自动磁盘修复 先登录到服务器,然后在/ ...

  7. CSS 图片加载完成再淡入显示

    一.方法 加载完成再显示:借助Image对象的onload事件,加载完时再把src赋给img标签的src: 淡人显示:起始opacity为0,利用transform过度到1 二.代码 <!DOC ...

  8. VC----对话框Dialog

    一个非模态对话框,当作主窗体的创建:(符合窗口创建的步骤) 第一步:补充一个模板,在RC脚本文件文件中,这是和普通窗口不一样的地方.这利益于编译器和链接器的支持呀. #include "wi ...

  9. web页面的加载顺序

    1.页面顺序 一个典型的web页面由于三个部分组成:html.css和JS.执行的顺序是: 在构造完HTML的dom结构时.触发DOMContentLoaded事件. 整个执行过程安装html的顺序来 ...

  10. 修改输入框placeholder文字默认颜色-webkit-input-placeholder

    html5为input添加了原生的占位符属性placeholder,高级浏览器都支持这个属性,例如: <input type="text" placeholder=" ...