4514: [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1305  Solved: 498
[Submit][Status][Discuss]

Description

有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。

若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,

那么这两个数字可以配对,并获得 ci×cj 的价值。

一个数字只能参与一次配对,可以不参与配对。

在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

Input

第一行一个整数 n。

第二行 n 个整数 a1、a2、……、an。

第三行 n 个整数 b1、b2、……、bn。

第四行 n 个整数 c1、c2、……、cn。

Output

一行一个数,最多进行多少次配对

Sample Input

3
2 4 8
2 200 7
-1 -2 1

Sample Output

4

HINT

n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5

Source

鸣谢Menci上传

当时一眼看出此题是费用流,建图很明显。//具体见代码

显然ans=maxflow;
然,碍于“在获得的价值总和不小于 0 的前提下”这个条件,只打了一个暴力。QAQ

#include<cstdio>
#include<cstdlib>
#include<iostream>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
using namespace std;
typedef long long i64;
const int N=4005;
const int M=5e5+5;
const i64 inf=10000000000000LL;//一定要够大
struct edge{int v,next;i64 cap,cost;}e[M];int tot=1,head[N];
int n,m,S,T,q[N],prev[N];bool vis[N];
i64 a[N],b[N],c[N];
i64 answ,ansf,dis[N];
void add(int x,int y,i64 z,i64 cost){
    e[++tot].v=y;e[tot].cap=z;e[tot].cost=cost;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].cap=0;e[tot].cost=-cost;e[tot].next=head[y];head[y]=tot;
}
bool spfa(){//非负费用最大流贪心流一定是正确的
    for(int i=S;i<=T;i++) vis[i]=0,dis[i]=-inf;
    unsigned short h=0,t=1;q[t]=S;dis[S]=0;
    while(h!=t){
        int x=q[++h];vis[x]=0;
        for(int i=head[x];i;i=e[i].next){
            if(e[i].cap&&dis[e[i].v]<dis[x]+e[i].cost){
                dis[e[i].v]=dis[x]+e[i].cost;
                prev[e[i].v]=i;
                if(!vis[e[i].v]){
                    vis[e[i].v]=1;//SLF优化还比朴素慢
                    //if(dis[e[i].v]>dis[x]){
                    //    q[h--]=e[i].v;
                    //}
                    //else{
                        q[++t]=e[i].v;
                    //}
                }
            }
        }
    }
    return answ+dis[T]>=0;//费用为非负的极限
}
void augment(){
    i64 flow=inf;
    if(dis[T]<0) flow=answ/(-dis[T]);
    for(int i=T;i!=S;i=e[prev[i]^1].v){
        flow=min(flow,e[prev[i]].cap);
    }
    for(int i=T;i!=S;i=e[prev[i]^1].v){
        e[prev[i]].cap-=flow;
        e[prev[i]^1].cap+=flow;
    }
    ansf+=flow;
    answ+=flow*dis[T];
}
i64 fpow(i64 a,i64 p,i64 mod){
    i64 res=1;
    for(;p;p>>=1,a=a*a%mod) if(p&1) res=res*a%mod;
    return res;
}
bool judge(i64 x){
    if(x<2) return 0;
    if(x==2) return 1;
    if(x&1^1) return 0;
    i64 a,t;
    for(int i=1;i<=10;i++){
        a=rand()%M;
        if(a>=x&&a%x==0) continue;
        t=fpow(a,x-1,x);
        if(t!=1) return 0;
    }
    return 1;
}
int main(){
    scanf("%d",&n);S=0,T=n<<1|1;
    for(int i=1;i<=n;i++) scanf(LL,&a[i]);
    for(int i=1;i<=n;i++){
        scanf(LL,&b[i]);
        add(S,i,b[i],0);
        add(i+n,T,b[i],0);
    }
    for(int i=1;i<=n;i++) scanf(LL,&c[i]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) continue;//暴力建图
            if(a[j]&&!(a[i]%a[j])&&judge(a[i]/a[j])){
                add(i,j+n,inf,c[i]*c[j]);
            }
            if(a[i]&&!(a[j]%a[i])&&judge(a[j]/a[i])){
                add(i,j+n,inf,c[i]*c[j]);
            }
        }
    }
    while(spfa()) augment();
    printf(LL,ansf/2);
    return 0;
}
时间: 2024-09-29 22:12:44

4514: [Sdoi2016]数字配对的相关文章

图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在

BZOJ 4514: [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1606  Solved: 608[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

[Bzoj4514][Sdoi2016]数字配对(费用流)

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2204  Solved: 865[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

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

[bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后能匹配的两点i,j 连 i->j' cap=inf cost=c[i]*c[j] 跑最大费用流,直到 cost<0 或 全部增广完 最后flow/2就是答案 1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #i

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

[BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最多进行多少次配对. Input 第一行一个整数 n. 第二行 n 个整数 a1.a2.…….an. 第三行 n 个整数 b1.b2.

Luogu P4068 [SDOI2016]数字配对(费用流)

Luogu P4068 [SDOI2016]数字配对(费用流) 根据质因子个数奇偶性划分肯定会形成一张二分图. 把所有的\(a\)分解质因数,记录其质因子个数. \(a_i \% a_j == 0\)且\(a_i\)的质因子比\(a_j\)质因子个数多1的时候,我们连边. 解决这个题目的关键是求出费用\(>0\)的时候的最大的流量. 我们要跑最大费用最大流,(具体实现是把边权取反) 这样在每一次的增广过程中,我们都可以保证费用最大且满足流最多. 但是写法有异议,待填坑. 原文地址:https:/

【BZOJ 4514】[Sdoi2016]数字配对 费用流

利用spfa流的性质,我直接拆两半,正解分奇偶(妙),而且判断是否整除且质数我用的是暴力根号,整洁判断质数个数差一(其他非spfa流怎么做?) #include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N=205; const int P=N; const int E=N*N/2; const int Inf=0x3f3f3f3f; const LL

[Sdoi2016]数字配对

Time Limit: 10 SecMemory Limit: 128 MBSubmit: 1411  Solved: 535[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最多进

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

Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最多进行多少次配对. Input 第一行一个整数 n. 第二行 n 个整数 a1.a2.--.an. 第三行 n 个整数 b1.b2.--.bn. 第四行 n 个整数 c1.c2.--