BZOJ 4514|SDOI 2016|数字配对|筛法|费用流
来源:互联网 发布:如何找回淘宝聊天记录 编辑:程序博客网 时间:2024/06/07 02:11
任意两个符合条件的数字,指数之和只差1,因此形成了二分图,每个点的可选择次数为
由于要求总价值和不得小于0,因此在最大费用最大流时,如果某一次增广会使得总价值和小于0,那么就只增广到刚好不小于0的时候就可以结束了。
#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;typedef long long ll;#define FOR(i,j,k) for(i=j;i<=k;++i)const int inf = 0x7f7f7f7f, N = 1000, M = 80005;namespace CostFlow { int q[M * 16], h[N], p[M], v[M], w[M], vis[N], pre[N]; int cnt = 1, tot, s, t; ll ans, dis[N], c[M]; void add(int x, int y, int z, ll d) { p[++cnt] = h[x]; v[cnt] = y; w[cnt] = z; c[cnt] = d; h[x] = cnt; p[++cnt] = h[y]; v[cnt] = x; w[cnt] = 0; c[cnt] = -d; h[y] = cnt; } bool spfa() { int i, u, f = 0, r = 0; memset(dis, 0x7f, sizeof dis); dis[s] = 0; q[r++] = s; pre[s] = -1; while (f < r) { u = q[f++]; vis[u] = 0; for (i = h[u]; i; i = p[i]) if (w[i] && dis[v[i]] > dis[u] + c[i]) { dis[v[i]] = dis[u] + c[i]; pre[v[i]] = i ^ 1; if (!vis[v[i]]) { vis[v[i]] = 1; q[r++] = v[i]; } } } return dis[t] != 0x7F7F7F7F7F7F7F7Fll; } bool end() { int u, sum = inf; for (u = pre[t]; u != -1; u = pre[v[u]]) sum = min(sum, w[u ^ 1]); if (ans + dis[t] * sum <= 0) { for (u = pre[t]; u != -1; u = pre[v[u]]) w[u] += sum, w[u ^ 1] -= sum; ans += dis[t] * sum; tot += sum; return 1; } else { tot -= ans / dis[t]; return 0; } } void solve() { ans = tot = 0; while (spfa() && end()); }}namespace Sleve { int vis[32001], p[32001], isprime[32001], cnt = 0; bool ok(int i, int j) { if (i < j) swap(i, j); if (!j || i % j) return 0; else for (int k = 0; k < cnt && i / j > p[k]; ++k) if (i / j % p[k] == 0) return 0; return 1; } void get_primes(int n) { int i, j; FOR(i,2,n) { if (!vis[i]) p[cnt++] = i, isprime[i] = 1; for (j = 0; j < cnt && i * p[j] <= n; ++j) { vis[i * p[j]] = 1; if (i % p[j] == 0) break; } } }}int a[N], b[N], odd[N], even[N];ll c[N];int main() { int i, j, k, sum, o = 0, e = 0, n; scanf("%d", &n); FOR(i,1,n) scanf("%d", a + i); FOR(i,1,n) scanf("%d", b + i); FOR(i,1,n) scanf("%lld", c + i); Sleve::get_primes(32000); FOR(i,1,n) { for (sum = j = 0; j < Sleve::cnt; ++j) for (k = a[i]; k % Sleve::p[j] == 0; k /= Sleve::p[j]) sum ^= 1; if (sum) odd[++o] = i; else even[++e] = i; } FOR(i,1,o) FOR(j,1,e) if (Sleve::ok(a[odd[i]], a[even[j]])) CostFlow::add(odd[i], even[j], inf, -c[odd[i]] * c[even[j]]); CostFlow::s = n + 1; CostFlow::t = n + 2; FOR(i,1,o) CostFlow::add(CostFlow::s, odd[i], b[odd[i]], 0); FOR(i,1,e) CostFlow::add(even[i], CostFlow::t, b[even[i]], 0); CostFlow::solve(); printf("%d", CostFlow::tot); return 0;}
4514: [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、……、cn。
Output
一行一个数,最多进行多少次配对
Sample Input
32 4 82 200 7-1 -2 1
Sample Output
4
HINT
0 0
- BZOJ 4514|SDOI 2016|数字配对|筛法|费用流
- bzoj 4514: [Sdoi2016]数字配对 费用流
- [二分图 费用流] BZOJ 4514 [Sdoi2016]数字配对
- bzoj 4514: [Sdoi2016]数字配对 (二分+费用流)
- BZOJ 4514: [Sdoi2016]数字配对(费用流)
- 4514: [Sdoi2016]数字配对|费用流
- bzoj 4514: [Sdoi2016]数字配对(二分图+费用最大流)
- 【SDOI 2013】【BZOJ 3130】费用流
- 【BZOJ4514】数字配对,费用流
- bzoj4514 数字配对 费用流
- BZOJ 4514 [Sdoi2016]数字配对
- 【BZOJ】4514: [Sdoi2016]数字配对
- BZOJ 2245 SDOI 2011 工作安排 费用流
- BZOJ 1927 SDOI 2010 星际竞速 费用流
- 【codevs 2306】【bzoj 1877】[SDOI 2009]晨跑(费用流)
- 【bzoj4514】[Sdoi2016]数字配对 费用流
- [BZOJ4514] [SDOI2016] 数字配对 - 费用流
- 费用流 【SDOI2016】 bzoj4514 数字配对
- Android换肤技术总结
- php实现简单验证码并且验证
- AVL树详解
- Android消息机制(Handler原理)
- win10 UWP 标签
- BZOJ 4514|SDOI 2016|数字配对|筛法|费用流
- oracle创建用户密码带特殊字符
- iOS Core Data
- Node.js 连接 MySQL 并进行数据库操作
- C++this指针
- 字符串和数组翻转
- RCNN学习笔记(9):OverFeat:Integrated Recognition, Localization and Detection using Convolutional Networks
- iOS一些疑惑点总结
- 知道这10个正则表达式,能让你少写1,000行代码