[bzoj4514][SDOI2016]数字配对——二分图
题目描述
题解:
这个题真的是巨坑,经过了6个WA,2个TLE,1个RE后才终于搞出来,中间都有点放弃希望了。。。
主要是一定要注意longlong!
下面开始说明题解。
朴素的想法是:
如果两个数字可以匹配,那么连一条边,那么问题就转化成了一个图的最大边匹配。
然而,一般图的最大边匹配是NP的,所以竞赛中一定不会出。
所以,这种题目一般会满足二分图性质。
我们可以跑几组大数据,进行二分图染色,发现的确是二分图。
仔细思考就可以发现,如果我们设f[i]为i的质因数个数,那么如果i和j可以配对,他们的f值奇偶性一定不同!
所以这个图一定是二分图。
跑一遍最小(最大)费用流就好辣。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn = 1e6;
const ll inf = 1e15;
int prime[maxn + 10], check[maxn + 10];
int s, t;
int n, cnt;
void init() {
memset(check, 0, sizeof(check));
cnt = 0;
for (int i = 2; i <= maxn; i++) {
if (!check[i])
prime[cnt++] = i;
for (int j = 0; j < cnt; j++) {
if (i * prime[j] > maxn)
break;
check[i * prime[j]] = true;
if (i % prime[j] == 0)
break;
}
}
}
const int N = 300;
ll a[N], b[N], c[N];
struct edge {
int from, to;
ll cap, flow, cost;
};
vector<ll> G[N];
vector<edge> E;
void add_edge(int from, int to, ll cap, ll cost) {
E.push_back((edge){from, to, cap, 0, cost});
E.push_back((edge){to, from, 0, 0, -cost});
int m = E.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
int calc(int x) {
int ret = 0;
for (int i = 0; prime[i] <= x; i++) {
if (x % prime[i] == 0) {
while (x % prime[i] == 0 && x) {
ret++;
x /= prime[i];
}
}
}
return ret;
}
int pre[N];
int inq[N];
ll dist[N];
ll fi[N];
bool spfa(ll &flow, ll &cost) {
for (int i = 0; i <= n + 1; i++) {
dist[i] = -inf;
}
memset(inq, 0, sizeof(inq));
dist[s] = 0, inq[s] = 1, pre[s] = 0, fi[s] = inf;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (int i = 0; i < G[u].size(); i++) {
edge &e = E[G[u][i]];
if (e.cap > e.flow && dist[e.to] < dist[u] + e.cost) {
dist[e.to] = dist[u] + e.cost;
pre[e.to] = G[u][i];
fi[e.to] = min(fi[u], e.cap - e.flow);
if (!inq[e.to]) {
q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if (dist[t] <= -inf)
return false;
if (cost + dist[t] * fi[t] < 0) {
ll temp = cost / (-dist[t]); //temp:还能够增加的流
flow += temp;
return false;
}
flow += fi[t];
cost += dist[t] * fi[t];
int u = t;
while (u != s) {
E[pre[u]].flow += fi[t];
E[pre[u] ^ 1].flow -= fi[t];
u = E[pre[u]].from;
}
return true;
}
ll mcmf(int s, int t) {
ll flow = 0;
ll cost = 0;
while (spfa(flow, cost))
;
return flow;
}
int main() {
init();
// freopen("input", "r", stdin);
scanf("%d", &n);
s = 0, t = n + 1;
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++)
scanf("%lld", &b[i]);
for (int i = 1; i <= n; i++)
scanf("%lld", &c[i]);
for (int i = 1; i <= n; i++) {
int f1 = calc(a[i]), f2;
for (int j = 1; j <= n; j++) {
f2 = calc(a[j]);
if ((f1 % 2 == 1) && ((f2 == f1 - 1 && a[i] % a[j] == 0) ||
(f1 == f2 - 1 && a[j] % a[i] == 0))) {
add_edge(i, j, inf, c[i] * c[j]);
}
}
if (f1 % 2 == 1)
add_edge(s, i, b[i], 0);
else
add_edge(i, t, b[i], 0);
}
ll ans = mcmf(s, t);
printf("%lld\n", ans);
}
[bzoj4514][SDOI2016]数字配对——二分图的更多相关文章
- bzoj4514 [Sdoi2016]数字配对
Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...
- bzoj4514 [Sdoi2016]数字配对(网络流)
Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对 ...
- BZOJ4514 [Sdoi2016]数字配对 【费用流】
题目 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×c ...
- BZOJ4514——[Sdoi2016]数字配对
有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的 ...
- bzoj4514: [Sdoi2016]数字配对--费用流
看了一眼题目&数据范围,觉得应该是带下界的费用流 原来想拆点变成二分图,能配对的连边,跑二分图,可行性未知 后来看到另外一种解法.. 符合匹配要求的数要满足:质因子的个数相差为1,且两者可整除 ...
- BZOJ4514[Sdoi2016]数字配对——最大费用最大流
题目描述 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci ...
- bzoj4514: [Sdoi2016]数字配对(费用流)
传送门 ps:费用流增广的时候费用和流量打反了……调了一个多小时 每个数只能参与一次配对,那么这就是一个匹配嘛 我们先把每个数分解质因数,记质因子总个数为$cnt_i$,那如果$a_i/a_j$是质数 ...
- 【bzoj4514】: [Sdoi2016]数字配对 图论-费用流
[bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后 ...
- 【BZOJ4514】[Sdoi2016]数字配对 费用流
[BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ...
随机推荐
- 笔记-restful
笔记-restful 1. restful简介 restful:representational state transfer,简称REST,描述了一个架构样式的网络系统. 值得注意的是RE ...
- 笔记-redis安装
笔记-redis安装配置 1. redis安装配置 1.1. windows环境安装 win8已有redis 查看版本:redis-server –version 想更新到5.0.0, ...
- P1021 邮票面值设计
P1021 邮票面值设计 题目描述 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1-MAX ...
- android onNewIntent 为什么要在onNewIntent的时候要显示的去调用setIntent
原因: 当调用到onNewIntent(intent)的时候,需要在onNewIntent() 中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getInte ...
- DNSSec
Domain Name System Security Extensions (DNSSEC)DNS安全扩展,是由IETF提供的一系列DNS安全认证的机制(可参考RFC2535).它提供了一种来源鉴定 ...
- 【转载】Unity3D研究院之静态自动检查代码缺陷与隐患
代码缺陷和代码错误的最大区别是,代码缺陷不影响游戏编译,而代码错误编译都不通过.但是代码缺陷会影响游戏发布后产生的一系列BUG..我今天无意间逛外国论坛发现的一个方法,使用了一下感觉挺给力的第一时间分 ...
- (整)Unreal渲染模块 框总览
@author: 黑袍小道 随缘查看 说明 由于搬山的渲染这部分担心自己理解错误,故而搬移官方下,后面整个完成再反过来更新 (这当且仅当做Unreal的帮助文档). 图形编程 模块 渲 ...
- HDU 4671 Backup Plan 构造
负载是否平衡只与前两列有关,剩下的只要与前两列不重复就随便放. 第一列我们按1-n这样循环放,第二列每次找个数最少的那个服务器放. #include <cstdio> #include & ...
- Java 实现二叉树的构建以及3种遍历方法
转载自http://ocaicai.iteye.com/blog/1047397 大二下学期学习数据结构的时候用C介绍过二叉树,但是当时热衷于java就没有怎么鸟二叉树,但是对二叉树的构建及遍历一直耿 ...
- 软工实践Alpha冲刺(10/10)
队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 完成所有界面的链接,整理与测试 展示GitHub当日代码/ ...