【LOJ】#2031. 「SDOI2016」数字配对
2018-06-01 10:05
302 查看
题解
这个图是个二分图,因为如果有一个奇环的话,我们会发现一个数变成另一个数要乘上个数不同的质数,显然不可能
然后我们发现这个不是求最大流,而是问一定价值的情况下最大流是多少,二分一个流量,加上一条边限流,然后求最小费用(其实是最大费用,把权值取反即可)是不是小于等于0,再看流量有没有流满
代码
#include <iostream> #include <cstdio> #include <vector> #include <algorithm> #include <cmath> #include <cstring> #include <map> //#define ivorysi #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define mp make_pair #define pb push_back #define fi first #define se second #define mo 974711 #define MAXN 15005 #define RG register using namespace std; typedef long long int64; typedef double db; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {putchar('-');x = -x;} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N; int a[405],b[405],col[405]; int64 c[405],g[405][405]; bool vis[405],E[405][405]; int totflow; int64 totval,pi1; struct node { int to,next,cap; int64 val; }Edge[500005]; int head[407],sumE,S,T; void add(int u,int v,int c,int64 a) { Edge[++sumE].to = v;Edge[sumE].next = head[u]; Edge[sumE].cap = c;Edge[sumE].val = a; head[u] = sumE; } void addtwo(int u,int v,int c,int64 a) { add(u,v,c,a);add(v,u,0,-a); } bool check(int x) { if(x == 1) return false; for(int i = 2 ; i <= x / i ; ++i) { if(x % i == 0) return false; } return true; } void dfs(int u,int id) { vis[u] = 1; col[u] = id; for(int v = 1 ; v <= N ; ++v) { int s = a[u],t = a[v]; if(s < t) swap(s,t); if(s % t == 0 && check(s / t)) { g[u][v] = g[v][u] = -c[u] * c[v]; E[u][v] = E[v][u] = 1; if(!vis[v]) dfs(v,id ^ 1); } } } int aug(int u,int C) { if(u == T) { totflow += C; totval += pi1 * C; return C; } int flow = 0; vis[u] = 1; for(int i = head[u] ; i ; i = Edge[i].next) { int v = Edge[i].to; if(Edge[i].cap && !vis[v] && Edge[i].val == 0) { int t = aug(v,min(C - flow,Edge[i].cap)); flow += t; Edge[i].cap -= t; Edge[i ^ 1].cap += t; if(flow == C) return flow; } } return flow; } bool modlabel() { int64 d = 1e18; for(int i = 1 ; i <= T ; ++i) { if(vis[i]) { for(int j = head[i] ; j ; j = Edge[j].next) { int v = Edge[j].to; if(Edge[j].cap && !vis[v] && Edge[j].val < d) d = Edge[j].val; } } } if(d == 1e18) return false; pi1 += d; for(int i = 1 ; i <= T ; ++i) { if(vis[i]) { for(int j = head[i] ; j ; j = Edge[j].next) { Edge[j].val -= d; Edge[j ^ 1].val += d; } } } return true; } bool check_flow(int MID) { memset(head,0,sizeof(head));sumE = 1; totval = 0;totflow = 0;pi1 = 0; for(int i = 1 ; i <= N ; ++i) { if(!col[i]) addtwo(N + 1,i,b[i],0); else addtwo(i,T,b[i],0); } for(int i = 1 ; i <= N ; ++i) { if(!col[i]) { for(int j = 1 ; j <= N ; ++j) { if(col[j] && E[i][j]) { addtwo(i,j,0x7fffffff,g[i][j]); } } } } addtwo(S,N + 1,MID,0); do { do{ memset(vis,0,sizeof(vis)); }while(aug(S,0x7fffffff)); }while(modlabel()); return totflow >= MID && totval <= 0; } void Init() { read(N); for(int i = 1 ; i <= N ; ++i) read(a[i]); for(int i = 1 ; i <= N ; ++i) read(b[i]); for(int i = 1 ; i <= N ; ++i) read(c[i]); for(int i = 1 ; i <= N ; ++i) if(!vis[i]) dfs(i,0); S = N + 2;T = N + 3; } void Solve() { int L = 0,R = 0; for(int i = 1 ; i <= N ; ++i) R += b[i]; R /= 2; while(L < R) { int mid = (L + R + 1) >> 1; if(check_flow(mid)) L = mid; else R = mid - 1; } out(L);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Init(); Solve(); return 0; }
相关文章推荐
- [Sdoi2016]数字配对
- bzoj4514【SDOI2016】数字配对
- [SDOI2016][bzoj4514] 数字配对 [费用流]
- [SDOI2016 Round1] 数字配对
- [SDOI2016 Round1] 数字配对
- [bzoj4514][SDOI2016]数字配对
- Cogs 2221. [SDOI2016 Round1] 数字配对
- BZOJ4514 [Sdoi2016]数字配对
- bzoj 4514: [Sdoi2016]数字配对(二分图+费用最大流)
- 4514: [Sdoi2016]数字配对 费用流
- cogs 2221. [SDOI2016 Round1] 数字配对
- 4514: [Sdoi2016]数字配对
- AC日记——[Sdoi2016]数字配对 bzoj 4514
- 【bzoj4514】[Sdoi2016]数字配对 费用流
- 【LOJ】#2066. 「SDOI2016」墙上的句子
- 4514: [Sdoi2016]数字配对
- bzoj 4514: [Sdoi2016]数字配对 (二分+费用流)
- 4514: [Sdoi2016]数字配对|费用流
- bzoj4514 [Sdoi2016]数字配对
- [二分图 费用流] BZOJ 4514 [Sdoi2016]数字配对