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

4514: [Sdoi2016]数字配对



Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2204  Solved: 865
[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上传

分析:


通过这道题我明白了这类题要去构造二分图模型。。

把奇数个质因子 偶数个质因子的放两边,然后匹配。

一直跑费用流跑到变负就好。或者边权取反,跑到变正就好。

wa在了把局部变量和整体变量定义一样了,还得了70,下次注意点把。

AC代码:


# include <iostream>
# include <cstdio>
# include <cmath>
# include <cstring>
using namespace std;
typedef long long LL;
const int N = 212;
const LL Inf = 1e18;
int a[N],n,cnt,prime[32001],s,t,one[N],two[N],head[N],dt;
bool vis[32001];LL c[N],b[N];
struct Edge{
    int to,nex;LL res,cost;
}edge[N * N * 4];
void AddEdge(int u,int v,LL w,LL c)
{
    edge[dt] = (Edge){v,head[u],w,c};
    head[u] = dt++;
    edge[dt] = (Edge){u,head[v],0,-c};
    head[v] = dt++;
}
void shai()
{
    for(int i = 2;i <= 32000;i++)
    {
        if(!vis[i])prime[++cnt] = i;
        for(int j = 1;j <= cnt;j++)
        {
            if(i * prime[j] > 32000)break;
            vis[i * prime[j]] = true;
            if(i % prime[j] == 0)break;
        }
    }
}
void init(){shai();memset(head,-1,sizeof head);}
void divide()
{
    for(int i = 1;i <= n;i++)
    {
        int sum = 0,x = a[i];
        for(int j = 1;j <= cnt;j++)
        {
            if(prime[j] > x)break;
            while(x % prime[j] == 0)x /= prime[j],sum++;
        }
        if(sum & 1)one[++one[0]] = i,AddEdge(s,i,b[i],0);
        else two[++two[0]] = i,AddEdge(i,t,b[i],0);
    }
}
bool pd(int x,int y)
{
    if(!x || !y || (x % y && y % x))return false;
    int k = max(x / y,y / x);
    if(k == 1)return false;
    for(int i = 1;i <= cnt;i++)if(prime[i] >= k)break;
    else if(k % prime[i] == 0)return false;
    return true;
}
int que[N * 10000],pre[N];LL dis[N];
bool spfa()
{
    for(int i = s;i <= t;i++)vis[i] = 0,pre[i] = -1,dis[i] = Inf;
    int H = 0,T = 0,u;que[T++] = s;dis[s] = 0;
    while(H != T)
    {
        u = que[H++];vis[u] = false;
        for(int i = head[u];~i;i = edge[i].nex)if(edge[i].res && dis[edge[i].to] > dis[u] + edge[i].cost)
        {
            dis[edge[i].to] = dis[u] + edge[i].cost;
            pre[edge[i].to] = i;
            if(!vis[edge[i].to])vis[edge[i].to] = true,que[T++] = edge[i].to;
        }
     }
     return pre[t] != -1;
}
void Mcmf(LL &ans,LL &cost)
{
    ans = cost = 0;
    while(spfa())
    {
     LL tmp = Inf;
     for(int i = pre[t];~i;i = pre[edge[i ^ 1].to])
     tmp = min(tmp,edge[i].res);
     if(cost + dis[t] * tmp <= 0)
     {
         for(int i = pre[t];~i;i = pre[edge[i ^ 1].to])
         edge[i].res -= tmp,edge[i ^ 1].res += tmp;
         ans += tmp;
         cost += dis[t] * tmp;
     }
     else {ans -= (cost / dis[t]);return;}
    }
}
int main()
{
    scanf("%d",&n);init();s = 0;t = n + 1;
    for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
    for(int i = 1;i <= n;i++)scanf("%lld",&b[i]);
    for(int i = 1;i <= n;i++)scanf("%lld",&c[i]);
    divide();
    for(int i = 1;i <= one[0];i++)
    {
        for(int j = 1;j <= two[0];j++)
        if(pd(a[one[i]],a[two[j]]))
        AddEdge(one[i],two[j],Inf,-c[one[i]] * c[two[j]]);
    }
    LL ans,cost;
    Mcmf(ans,cost);
    printf("%lld\n",ans);
}

原文地址:https://www.cnblogs.com/lzdhydzzh/p/8757397.html

时间: 2024-10-09 01:51:35

[Bzoj4514][Sdoi2016]数字配对(费用流)的相关文章

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

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

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

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

【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.

【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

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

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

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.--

[bzoj4514] [Sdoi2016]数字配对

费用流.. 先把a数组里的数全部质因数分解,判断ai/aj是否为质数,就看质因数互相抵消后是不是只剩一个质因数. 满足条件的数就连边 接下来我想拆点建二分图..然而由题解可得,连边的两个数 的质因数个数 的奇偶性肯定不同.. 就相当于自带黑白染色...所以奇数个连汇,偶数个连源就行了= = 因为有价值总和不小于0的限制.所以找到一条价值为负的增广路后,不一定能流满. 但是因为求费用流的原始对偶算法自带限制流量的功能..所以其实改一个数就能照常多路增广了= = 1 #include<cstdio>

[SDOI2016][bzoj4514] 数字配对 [费用流]

题面 传送门 思路 一个数字能且只能匹配一次 这引导我们思考:一次代表什么?代表用到一定上限(b数组)就不能再用,同时每用一次会产生价值(c数组) 上限?价值?网络流! 把一次匹配设为一点流量,那产生的价值不就是费用了吗? 我们考虑把一种数字抽象成一个点,可以匹配的数字之间连边,费用为c[i]*c[j],流量上限为..... 等等,流量上限怎么设? 而且还有一个问题:这里的匹配是双向的,虽然可以$O\left(n^2\right)$求出所有匹配对,但是网络流要求是单向边啊! 别急,我们先来分析一

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

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