数字配对

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

  第一行一个整数 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

Solution

  显然是一个费用流,并且这可以是一个二分图,由于 ai/aj 要是质数,那显然可以根据质因子个数的奇偶分类。

  然后跑一跑最大费用最大流。判断一下值要>=0即可统计入答案。mmpBearChild查了一个下午错,发现是INF开小了qaq。

Code

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<map>
using namespace std;
typedef long long s64; const int ONE = *;
const int INF = ; int n;
int a[ONE], b[ONE], c[ONE];
s64 dist[ONE];
int vis[ONE], q[ONE*], pre[ONE];
int first[ONE], go[ONE], next[ONE], pas[ONE], from[ONE], tot;
int pNum[ONE];
int odd[ONE],Onum, eve[ONE],Enum;
int S, T, Ans;
int prime[ONE], isp[ONE], p;
s64 Val, w[ONE]; int get()
{
int res=,Q=;char c;
while( (c=getchar())< || c> )
if(c=='-')Q=-;
res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res*Q;
} void Getp(int MaxN)
{
for(int i=; i <= MaxN; i++)
{
if(!isp[i]) prime[++p] = i;
for(int j=; j <= prime[p], i*prime[j] <= MaxN; j++)
{
isp[i * prime[j]] = ;
if(i % prime[j] == ) break;
}
}
} int Factor(int x)
{
int res = ;
while(x != )
{
for(int i=; i<=p; i++)
if(x % prime[i] == )
{
x /= prime[i];
res++;
break;
}
}
return res;
} int PD(int x, int y)
{
if(x > y) swap(x, y);
if(x== || y== || y%x!=) return ;
x = y / x;
for(int i=; i<x; i++)
if(x % i == ) return ;
return ;
} int Add(int u, int v, int flow, s64 z)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v; pas[tot]=flow; w[tot]=z; from[tot]=u;
next[++tot]=first[v]; first[v]=tot; go[tot]=u; pas[tot]=; w[tot]=-z; from[tot]=v;
} bool Bfs()
{
for(int i=S; i<=T; i++) dist[i] = -1e18;
int tou = , wei = ;
q[] = S; vis[S] = ; dist[S] = ;
while(tou < wei)
{
int u = q[++tou];
for(int e=first[u]; e; e=next[e])
{
int v=go[e];
if(dist[v] < dist[u] + w[e] && pas[e])
{
dist[v] = dist[u] + w[e];
pre[v] = e;
if(!vis[v])
{
q[++wei] = v;
vis[v] = ;
}
}
}
vis[u] = ;
}
return dist[T] != -1e18;
} void Deal()
{
int x = INF;
for(int e=pre[T]; e; e=pre[from[e]]) x = min(x, pas[e]);
if(Val + dist[T] * x >= )
{
for(int e=pre[T]; e; e=pre[from[e]])
{
pas[e] -= x;
pas[((e-)^)+] += x;
}
Val += dist[T] * x;
Ans += x;
return;
}
printf("%d", Ans - Val / dist[T]);
exit();
} int main()
{
Getp(ONE);
n = get();
for(int i=; i<=n; i++) a[i] = get(), pNum[i] = Factor(a[i]);
for(int i=; i<=n; i++) b[i] = get();
for(int i=; i<=n; i++) c[i] = get(); S = ; T = n+;
for(int i=; i<=n; i++)
{
if(pNum[i] & ) Add(S,i, b[i],), odd[++Onum] = i;
else Add(i,T, b[i],), eve[++Enum] = i;
} for(int i=; i<=Onum; i++)
for(int j=; j<=Enum; j++)
{
int x = odd[i], y = eve[j];
if( PD(a[x], a[y]) )
Add(x,y, INF,(s64)c[x]*c[y]);
} while(Bfs()) Deal();
printf("%d", Ans - Val / dist[T]);
}

【BZOJ4514】【SDOI2016】数字配对 [费用流]的更多相关文章

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

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

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

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

  3. BZOJ 4514: [Sdoi2016]数字配对 [费用流 数论]

    4514: [Sdoi2016]数字配对 题意: 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数 ...

  4. BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)

    BZOJ 洛谷 \(Solution\) 很显然的建二分图后跑最大费用流,但有个问题是一个数是只能用一次的,这样二分图两部分都有这个数. 那么就用两倍的.如果\(i\)可以向\(j'\)连边,\(j\ ...

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

    利用spfa流的性质,我直接拆两半,正解分奇偶(妙),而且判断是否整除且质数我用的是暴力根号,整洁判断质数个数差一(其他非spfa流怎么做?) #include <cstdio> #inc ...

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

    链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4514 思路 EK直接贪心做 <0的时候加上剩余返回 二分图a->b的时候 把b- ...

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

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

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

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

  9. [bzoj4514]数字配对[费用流]

    今年SDOI的题,看到他们在做,看到过了一百多个人,然后就被虐惨啦... 果然考试的时候还是打不了高端算法,调了...几天 默默地yy了一个费用流构图: 源连所有点,配对的点连啊,所有点连汇... 后 ...

随机推荐

  1. sql查询 同一个字段下另一个字段个数

    select seriesid , count(reportid) from reportsystem group by seriesidhaving count(reportid) > 1

  2. android 出现Make sure the Cursor is initialized correctly before accessing data from it

    Make sure the Cursor is initialized correctly before accessing data from it 详细错误是:java.lang.IllegalS ...

  3. Android api level对照表

    转自:blog.csdn.net/lihenair/article/details/49869299 Platform Version API Level VERSION_CODE Notes And ...

  4. cacti 安装perl 和XML::Simple

    一.安装perl #tar zxvf perl-5.20.1.tar.gz #cd perl-5.20.1  #./Configure -de  #make  #make test  #make in ...

  5. Redis 学习之集群

    该文使用centos6.5 64位  redis3.2.8 一.  redis-cluster架构图 集群通信:所有redis节点之间通过PING-PONG机制彼此互联,内部使用二进制鞋子优化传输速度 ...

  6. table中的td限制宽度width也不能让字符过长变成省略号生效?

    table中的td限制宽度width也不能让字符过长变成省略号生效? http://blog.csdn.net/java_mr_zheng/article/details/49423247 CSS t ...

  7. MATLAB中的randi函数

    randi Pseudorandom integers from a uniform discrete distribution.来自一个均匀离散分布的伪随机整数 R = randi(IMAX,N) ...

  8. hadoop 把mapreduce任务从本地提交到hadoop集群上运行

    MapReduce任务有三种运行方式: 1.windows(linux)本地调试运行,需要本地hadoop环境支持 2.本地编译成jar包,手动发送到hadoop集群上用hadoop jar或者yar ...

  9. 【原创】Oracle Not In 导致有存在Null的数据被过滤

    解决方法:  WHERE  NVL(ID,)  NOT IN ('') 注:红字部分不相等就可以

  10. 消息传递 树形DP

    非常妙的树形DP:由于n很小,我们可以枚举每一个点作为第一个节点,计算其时间花费 那么问题就转化为对于给点节点求花费时间. 通过观察,显然我们会发现先传给花费时间多的人更加合算,因为这样可以最大限度的 ...