重点是如何找到可以配对的\(a[i]\)和\(a[j]\)。

把\(a[i]\)分解质因数。设\(a[i]\)分解出的质因数的数量为\(cnt[i]\)。

设\(a[i]\geq a[j]\)

那么\(a[i]\)可以和\(a[j]\)配对需要满足\(a[i]\)%\(a[j]==0\)&&\(cnt[i]==cnt[j]+1\)

证明显然。

然后我们按\(cnt[i]\)的奇偶分成两部分,然后如果\(a[i]\)和\(a[j]\)可以配对(假设a[i]在左边)从\(i\)向\(j\)连一条费用为\(c[i]*c[j\)],流量为\(INF\)的边。

然后\(S\)向左部点连费用为\(0\),流量为\(b[i]\)的边。

然后每一个右部点向\(T\)连费用为\(0\),流量为\(b[i]\)的边。

跑费用流。

因为费用流优先走最长路。

所以我们可以贪心。

当总费用刚好为负时结束就好了。

具体来说这次增广前的总费用为\(tot\),总流量为\(w\)。

然后这次最长路长度为\(x\),可以增广的流量为\(tmp\)。

且\(tot+x*tmp<0\),答案就是\(w+\lfloor \frac{tot}{x} \rfloor\)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define int long long
const int N=233;
const int INF=1e14;
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;
}
int book[101000],prime[100100],tot;
void pre_work(int n){
for(int i=2;i<=n;i++){
if(book[i]==0)prime[++tot]=i;
for(int j=1;j<=tot&&prime[j]*i<=n;j++){
book[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
int work(int x){
int tmp=0;
for(int i=1;prime[i]*prime[i]<=x;i++)
if(x%prime[i]==0){
while(x%prime[i]==0)x/=prime[i],tmp++;
}
if(x>1)tmp++;
return tmp;
}
struct edge{
int to,nxt,flow,cost;
}e[N*N*2];
int cnt=1,head[N];
void add_edge(int u,int v,int flow,int cost){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
e[cnt].flow=flow;
e[cnt].cost=cost;
head[u]=cnt;
cnt++;
e[cnt].nxt=head[v];
e[cnt].to=u;
e[cnt].flow=0;
e[cnt].cost=-cost;
head[v]=cnt;
}
int dis[N],vis[N],road[N],S,T,tmp,ans;
bool spfa(){
for(int i=S;i<=T;i++)dis[i]=INF;
queue<int> q;
q.push(S);
dis[S]=0;
vis[S]=1;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(e[i].flow&&dis[v]>dis[u]+e[i].cost){
dis[v]=dis[u]+e[i].cost;
road[v]=i;
if(vis[v]==0){
vis[v]=1;
q.push(v);
}
}
}
}
if(dis[T]==INF)return false;
int mn=INF;
for(int i=T;i!=S;i=e[road[i]^1].to)
mn=min(e[road[i]].flow,mn);
if(tmp+mn*dis[T]>0){
ans+=-tmp/dis[T];
return false;
}
tmp+=mn*dis[T];
ans+=mn;
for(int i=T;i!=S;i=e[road[i]^1].to){
e[road[i]].flow-=mn;
e[road[i]^1].flow+=mn;
}
return true;
}
int n,a[N],b[N],c[N],w[N];
signed main(){
pre_work(100000);
n=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)b[i]=read();
for(int i=1;i<=n;i++)c[i]=read();
for(int i=1;i<=n;i++)w[i]=work(a[i]);
S=0;T=n+1;
for(int i=1;i<=n;i++)
if(w[i]%2==1)add_edge(S,i,b[i],0);
else add_edge(i,T,b[i],0);
for(int i=1;i<=n;i++){
if(w[i]%2==0)continue;
for(int j=1;j<=n;j++){
if(w[j]%2==1)continue;
if((a[j]%a[i]==0&&w[j]==w[i]+1)||(a[i]%a[j]==0&&w[i]==w[j]+1))
add_edge(i,j,INF,-c[i]*c[j]);
}
}
while(spfa());
printf("%lld",ans);
return 0;
}

[SDOI2016]数字配对(费用流+贪心+trick)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

    数字配对 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ...

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

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

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

    题面 传送门 思路 一个数字能且只能匹配一次 这引导我们思考:一次代表什么?代表用到一定上限(b数组)就不能再用,同时每用一次会产生价值(c数组) 上限?价值?网络流! 把一次匹配设为一点流量,那产生 ...

随机推荐

  1. [bzoj3932][CQOI2015]任务查询系统_主席树

    任务查询系统 bzoj-3932 CQOI-2015 题目大意:最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的任务用三元组(Si,Ei,Pi)描述 ...

  2. js 跨浏览器获取事件信息模块

    var EventUtil = { addHandler: function(element, type, handler) { if (element.addEventListener) { ele ...

  3. 多版本号并发控制(MVCC)在实际项目中的应用

    近期项目中遇到了一个分布式系统的并发控制问题.该问题能够抽象为:某分布式系统由一个数据中心D和若干业务处理中心L1,L2 - Ln组成:D本质上是一个key-value存储,它对外提供基于HTTP协议 ...

  4. JS禁用右键+禁用Ctrl+u+禁用F12

    第一种方法: , , ]; document.oncontextmenu = new Function("event.returnValue=false;"),//禁用右键 doc ...

  5. C++开发人脸性别识别教程(19)——界面美化

    在这篇博文中将完毕<C++开发人脸性别识别>的收尾工作.主要内容分为两部分:加入视频暂定功能.界面规范化. 一 视频暂停功能 严格来说这个视频暂定功能算是视频人脸性别识别的一个遗留问题,本 ...

  6. Java web測试分为6个部分

    1.功能測试 2.性能測试(包含负载/压力測试)3.用户界面測试 4. 兼容性測试 5.  安全測试  6.接口測试   1 功能測试 1.1 链接測试 链接測试可分为三个方面. 首先,測试全部链接是 ...

  7. 如何让 ssh 允许以 root 身份登录

    默认情况下,Pack 上的 root 用户不能用通过密码来远程登录,可以用一下命令来做:(注意要在 root 权限下) sed -i 's/PermitRootLogin\swithout-passw ...

  8. php 获取随机字符串(原创)

    //获取随机数字字母字符串 function get_rand_str($len=8){ $randArr=array_merge(range(0,9),range('a','z'),range('A ...

  9. Webpack 中的 Tree Shaking

    Tree Shaking Tree shaking 用于描述移除JavaScript上下文中的未引用代码(dead-code). 为了更方便地理解tree shaking,我们可以将应用程序想象成一棵 ...

  10. TexturePacker贴图打包工具

    1.该软件是收费的,不过对于这么一款实用的工具来说,物有所值,下载地址 http://www.codeandweb.com/texturepacker 2.openGL载入纹理图片的时候,所用内存是会 ...