COGS 2221. [SDOI2016 Round1] 数字配对

http://www.cogs.pro/cogs/problem/problem.php?pid=2221

★★★   输入文件:menci_pair.in   输出文件:menci_pair.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

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

若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 aiaj 是一个质数,那么这两个数字可以配对,并获得 ci×cj 的价值。

一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

【输入格式】

第一行一个整数 n。
第二行 n 个整数 a1、a2、……、an。
第三行 n 个整数 b1、b2、……、bn。
第四行 n 个整数 c1、c2、……、cn。

【输出格式】

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

【样例输入】

3

2 4 8

2 200 7

-1 -2 1

【样例输出】

4

【提示】

测试点 1 ~ 3:n≤10,ai≤109,bi=1,∣ci∣≤105;
测试点 4 ~ 5:n≤200,ai≤109,bi≤105,ci=0;
测试点 6 ~ 10:n≤200,ai≤109,bi≤105,∣ci∣≤105。

【来源】

SDOI2016 Round1 Day1

费用流u

构图方法:(以样例为例)

1、2可以配对;2、3可以配对

注意,这里若a与b可以配对,则既要由a向b连边,又要由b向a连同样的边,最后答案除以2

原因:

1、如果只由a向b连,那么如果又有一条边由c连向a,边流量都为inf,这样从源点向a用了,由a向汇点又用了,应该统计的是2次之和,但实际只统计了其中一次

2、a向b连边m、b向a连同样的边n,这样费用流跑m一定跑n,这样就可以把1中2次汇总,因为对应边流量相等,所以答案要除2

因为要总价值和>=0,所以每次跑最大费用,

如果本次跑出的最大价值+已累积的价值>=0,继续跑

反之,次数+已累计价值/-本次单位流量最大费用,结束

因为累计价值不可能为负,而题目要求总价值和>=0,若满足反之条件,本次最大费用<0 且 本次最大费用总和绝对值>已累计价值,所以就看已累计价值最大能抵消多少次本次的负价值

#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[],b[],c[];
int tot=,src,dec;
int front1[],from[],next1[],to1[];
bool v[];
int n,fa[];
long long dis[],sum_cost,cost[],cap[];
int sum_flow;
queue<int>que;
bool judge(int x)
{
for(int i=;i<=sqrt(x);i++)
if(x%i==) return false;
return true;
}
void insert_edge(int u,int v,long long w,long long val)
{
to1[++tot]=v;from[tot]=u;next1[tot]=front1[u];front1[u]=tot;cap[tot]=w;cost[tot]=val;
to1[++tot]=u;from[tot]=v;next1[tot]=front1[v];front1[v]=tot;cap[tot]=;cost[tot]=-val;
}
bool spfa()
{
for(int i=;i<=dec;i++) dis[i]=-1e15,fa[i]=;
memset(v,,sizeof(v));
que.push(src);v[src]=true;
dis[]=;
while(!que.empty())
{
int now=que.front();
que.pop();v[now]=false;
for(int i=front1[now];i;i=next1[i])
{
if(dis[now]+cost[i]>dis[to1[i]]&&cap[i]>)
{
dis[to1[i]]=dis[now]+cost[i];
fa[to1[i]]=i;
if(!v[to1[i]])
{
que.push(to1[i]);
v[to1[i]]=true;
}
}
}
}
if(dis[dec]!=-1e10) return true;
return false;
}
void work()
{
while(spfa())
{
long long tmp=1e15,k=;
for(int i=fa[dec];i;i=fa[from[i]]) tmp=min(cap[i],tmp);
if(sum_cost+dis[dec]*1ll*tmp>=)
{
sum_cost+=dis[dec]*tmp;sum_flow+=tmp;
for(int i=fa[dec];i;i=fa[from[i]])
{
cap[i]-=tmp;cap[i^]+=tmp;
}
}
else
{
sum_flow+=int(sum_cost/abs(dis[dec]));
break;
}
}
printf("%d",sum_flow/);
return ;
}
int main()
{
freopen("menci_pair.in","r",stdin);
freopen("menci_pair.out","w",stdout);
scanf("%d",&n);
dec=n+<<;
for(int i=;i<=n;i++) scanf("%d",&a[i]);
for(int i=;i<=n;i++) scanf("%d",&b[i]);
for(int i=;i<=n;i++) scanf("%d",&c[i]);
for(int i=;i<=n;i++) insert_edge(src,i<<,b[i],);
for(int i=;i<=n;i++) insert_edge(i<<|,dec,b[i],);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
{
if(a[i]<=a[j]) continue;
if(a[i]%a[j]==&&judge(a[i]/a[j]))
{
insert_edge(j<<,i<<|,1e15,1ll*c[i]*c[j]);
insert_edge(i<<,j<<|,1e15,1ll*c[i]*c[j]);
} }
work();
}

学长说了另外2种方法:

1、根据分解质因数的指数和的奇偶性,将所有点分为2个集合,构建二分图(标解,不想写就没写)

学长AC代码链接:http://www.cnblogs.com/harden/p/6399396.html

2、根据整除关系构成的链,将所有点分为2个集合,每条链的起点在哪个集合里随便,构建二分图,与1不同的地方就是链的起点在哪个集合的问题

(这个写了,然而调了一晚上+半上午,COGS提交最终3A 1W 1RE 5T ,法2正确性、代码正确性有待验证)

#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[201],b[201],c[201];
int front[210],next[160001],to[160001],tot,src,dec;
int front1[210],from[160001],next1[160001],to1[160001];
bool use_in[210],use_out[210],v[210];
int n,fa[210];
long long dis[210],sum_cost,cost[160001],cap[160001];
int sum_flow;
struct node1
{
int point,id;
};
queue<node1>q;
queue<int>que;
bool judge(int x)
{
for(int i=2;i<=sqrt(x);i++)
if(x%i==0) return false;
return true;
}
void add(int u,int v)
{
to[++tot]=v;next[tot]=front[u];front[u]=tot;
use_in[v]=true;use_out[u]=true;
}
void insert_edge(int u,int v,long long w,long long val)
{
to1[++tot]=v;from[tot]=u;next1[tot]=front1[u];front1[u]=tot;cap[tot]=w;cost[tot]=val;
to1[++tot]=u;from[tot]=v;next1[tot]=front1[v];front1[v]=tot;cap[tot]=0;cost[tot]=-val;
}
bool spfa()
{
for(int i=1;i<=dec;i++) dis[i]=-1e15,fa[i]=0;
que.push(src);v[src]=true;
while(!que.empty())
{
int now=que.front();
que.pop();v[now]=false;
for(int i=front1[now];i;i=next1[i])
{
if(dis[now]+1ll*cost[i]>dis[to1[i]]&&cap[i]>0)
{
dis[to1[i]]=dis[now]+1ll*cost[i];
fa[to1[i]]=i;
if(!v[to1[i]])
{
que.push(to1[i]);
v[to1[i]]=true;
}
}
}
}
if(dis[dec]!=-1e15) return true;
return false;
}
void work()
{
while(spfa())
{
long long tmp=1e15;
for(int i=fa[dec];i;i=fa[from[i]]) tmp=min(cap[i],tmp);
if(sum_cost+dis[dec]*1ll*tmp>=0)
{
sum_cost+=dis[dec]*tmp;sum_flow+=tmp;
for(int i=fa[dec];i;i=fa[from[i]])
{
cap[i]-=tmp;cap[i^1]+=tmp;
}
}
else
{
sum_flow+=int(sum_cost/abs(dis[dec]));
break;
}
}
printf("%d",sum_flow);
return ;
}
int main()
{
freopen("menci_pair.in","r",stdin);
freopen("menci_pair.out","w",stdout);
scanf("%d",&n);
dec=n+1;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(a[i]<=a[j]) continue;
if(!a[j]) continue;
if(a[i]%a[j]==0&&judge(a[i]/a[j]))
{
add(j,i);
}
}
tot=1;
for(int i=1;i<=n;i++)
if(!use_in[i])
{
insert_edge(src,i,b[i],0);
q.push((node1){i,1});
}
while(!q.empty())
{
node1 now=q.front();q.pop();
for(int i=front[now.point];i;i=next[i])
{
int t=to[i];
if(now.id%2)
{
insert_edge(now.point,t,1e15,1ll*c[now.point]*c[t]);
insert_edge(t,dec,b[t],0);
q.push((node1){t,now.id+1});
}
else
{
insert_edge(t,now.point,1e15,1ll*c[now.point]*c[t]);
insert_edge(src,t,b[t],0);
q.push((node1){t,now.id+1});
}
}
}
work();
}

错误代码

[SDOI2016 Round1] 数字配对的更多相关文章

  1. Cogs 2221. [SDOI2016 Round1] 数字配对(二分图)

    [SDOI2016 Round1] 数字配对 ★★★ 输入文件:menci_pair.in 输出文件:menci_pair.out 简单对比 时间限制:1 s 内存限制:128 MB [题目描述] 有 ...

  2. cogs 2221. [SDOI2016 Round1] 数字配对

    ★★ 输入文件:pair.in 输出文件:pair.out 简单对比 时间限制:1 s 内存限制:128 MB [题目描述] 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两 ...

  3. 「SDOI2016」数字配对

    「SDOI2016」数字配对 题目大意 传送门 题解 \(a_i\) 是 \(a_j\) 的倍数,且 \(\frac{a_i}{a_j}\) 是一个质数,则将 \(a_i,a_j\) 质因数分解后,其 ...

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

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

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

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

  6. 【LOJ】#2031. 「SDOI2016」数字配对

    题解 这个图是个二分图,因为如果有一个奇环的话,我们会发现一个数变成另一个数要乘上个数不同的质数,显然不可能 然后我们发现这个不是求最大流,而是问一定价值的情况下最大流是多少,二分一个流量,加上一条边 ...

  7. loj2031 「SDOI2016」数字配对

    跑最大费用最大流,注意到每次 spfa 出来的 cost 一定是越来越少的,啥时小于 \(0\) 了就停了吧. #include <iostream> #include <cstri ...

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

    4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status ...

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

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

随机推荐

  1. 调研ANDRIOD平台的开发环境的发展演变

    在同学的推荐下,我选用学习eclipse这个软件,参考了这个网址的教程开始了一步一步的搭建之路. http://jingyan.baidu.com/article/bea41d437a41b6b4c5 ...

  2. iOS开发值得收藏的博客

    http://kobedai.me/ objc.io PS:经典,内容深而广objc中国NSHipster PS:很多小细节NSHipster 中文版唐巧的技术博客 PS:LZ是唐巧的脑残粉…OneV ...

  3. 移动web适配利器-rem

    移动web适配利器-rem 前言 提到rem,大家首先会想到的是em,px,pt这类的词语,大多数人眼中这些单位是用于设置字体的大小的,没错这的确是用来设置字体大小的,但是对于rem来说它可以用来做移 ...

  4. java.lang.NoSuchMethodError: org.hibernate.integrator.internal.IntegratorServiceImpl.<init>(Ljava/util/LinkedHashSet;Lorg/hibernate/boot/registry/classloading/spi/ClassLoaderService;)

    需要:4.3及以上的版本才能用StandardServiceRegistryBuilder() hibernate-core-4.3.11.Final.jar version:4.3 ServiceR ...

  5. 016 Java中的动态代理

    作者:nnngu GitHub:https://github.com/nnngu 博客园:http://www.cnblogs.com/nnngu 简书:https://www.jianshu.com ...

  6. System Board Replacement Notice

    System Board Replacement Notice System Board Replacement Notice for TP 770E and TP 600 Restoring the ...

  7. 洛谷 P1341 无序字母对 解题报告

    P1341 无序字母对 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 ...

  8. 【bzoj3926】 Zjoi2015—诸神眷顾的幻想乡

    http://www.lydsy.com/JudgeOnline/problem.php?id=3926 (题目链接) 题意 给出一棵树,每个节点有一个编号,范围在${[0,9]}$.一个序列是指树上 ...

  9. LINUX第四周学习

    <Linux内核设计与实现>第四周读书笔记——第五章 5.1 与内核通信57 系统调用在用户空间进程和硬件设备之间添加了一个中间层,该层主要作用有三个: 首先它为用户空间提供了一种硬件的抽 ...

  10. Redis中国用户组|唯品会Redis cluster大规模生产实践

    嘉宾:陈群 很高兴有机会在Redis中国用户组给大家分享redis cluster的生产实践.目前在唯品会主要负责redis/hbase的运维和开发支持工作,也参与工具开发工作 Outline 一.生 ...