zoukankan      html  css  js  c++  java
  • 4514: [Sdoi2016]数字配对

    4514: [Sdoi2016]数字配对

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2197  Solved: 859
    [Submit][Status][Discuss]

    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

    3
    2 4 8
    2 200 7
    -1 -2 1

    Sample Output

    4

    分析

    原来想的思路是二分+最大费用最大流。(费用就是价值和,流量为匹配次数)

    二分最大流k,算出费用判断是否大于0。

    后来在网上看到题解,可以智跑一遍费用流,因为求费用流的过程中每次增广的路径费用都是最大的,那么当一次增广完成后,如果加上当前的费用小于0了,那么不需要继续增广了,因为往后增广的费用只会更小。然后现在的费用是大于0的,还可以继续匹配一些的,所以再继续匹配尽量多的(代码64行)。

    因为i->j+n和j->i+n是一样的,所以开始时想的是连一条,但是这样是不行的,因为可能存在1->2流了3的流量,2->3流了3的流量,而2只有5个。而如果两条边都建上,就满足了,因为他们的花费是一样的,跑了一条,一定会跑另一条,所以连个S->i和i+n->T两条边都会减少一样的流量。

    code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<iostream>
     6 
     7 using namespace std;
     8 typedef long long LL;
     9 
    10 const int N = 510;
    11 const LL INF = 1e18;
    12 struct Edge{
    13     int from,to,nxt;LL cap,cost;
    14     Edge() {}
    15     Edge(int a,int b,LL c,LL d,int f) {from=a,to=b,cap=c,cost=d,nxt=f;}
    16 }e[100100];
    17 int a[N],b[N],c[N];
    18 bool vis[N];
    19 int head[N],pre[N],q[100100];
    20 int n,m,tot = 1,S,T,L,R;
    21 LL dis[N],Sf,Sc; // sum flow ,sum cost
    22 
    23 int read() {
    24     int x = 0,f = 1;char ch = getchar();
    25     for (; ch<'0'||ch>'9'; ch=getchar()) if(ch=='-') f=-1;
    26     for (; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
    27     return x * f;
    28 }
    29 bool pd(int x,int y) {
    30     if (x % y != 0) return false;
    31     int t = x/y;
    32     for (int i=2; i*i<=t; ++i) 
    33         if (t % i == 0) return false;
    34     return true;
    35 }
    36 void add_edge(int u,int v,LL cap,LL cost) {
    37     e[++tot] = Edge(u,v,cap,cost,head[u]);head[u] = tot;
    38     e[++tot] = Edge(v,u,0,-cost,head[v]);head[v] = tot;
    39 }
    40 bool spfa() {
    41     for (int i=1; i<=T; ++i) dis[i] = -INF;
    42     L = 1,R = 0;
    43     dis[S] = 0;
    44     q[++R] = S;vis[S] = true;pre[S] = 0;
    45     while (L <= R) {
    46         int u = q[L++];
    47         for (int i=head[u]; i; i=e[i].nxt) {
    48             int v = e[i].to;
    49             if (e[i].cap > 0 && dis[v] < dis[u] + e[i].cost) {
    50                 pre[v] = i;
    51                 dis[v] = dis[u] + e[i].cost;
    52                 if (!vis[v]) q[++R] = v,vis[v] = true;
    53             }
    54         }
    55         vis[u] = false;
    56     }
    57     return dis[T] != -INF;
    58 }
    59 bool mcf() {
    60     LL mf = INF; // min flow
    61     for (int i=T; i!=S; i=e[pre[i]].from) 
    62         mf = min(e[pre[i]].cap,mf);
    63     if (Sc+dis[T]*mf < 0) {
    64         Sf += (LL)(Sc/(abs(dis[T])));
    65         return false;
    66     }
    67     for (int i=T; i!=S; i=e[pre[i]].from) 
    68         e[pre[i]].cap -= mf,e[pre[i]^1].cap += mf;
    69     Sc += mf * dis[T]; // ---
    70     Sf += mf;
    71     return true;
    72 }
    73 
    74 int main () {
    75     n = read();
    76     for (int i=1; i<=n; ++i) a[i] = read();
    77     for (int i=1; i<=n; ++i) b[i] = read();
    78     for (int i=1; i<=n; ++i) c[i] = read();
    79     S = n+n+1,T = n+n+2;
    80     for (int i=1; i<=n; ++i) 
    81         for (int j=1; j<=n; ++j) {
    82             if (a[i] < a[j] || i==j) continue;
    83             if (pd(a[i],a[j])) {
    84                 add_edge(i,j+n,INF,1ll*c[i]*c[j]);
    85                 add_edge(j,i+n,INF,1ll*c[i]*c[j]);
    86             }        
    87         }
    88     for (int i=1; i<=n; ++i) {
    89         add_edge(S,i,(LL)b[i],0);
    90         add_edge(i+n,T,(LL)b[i],0);
    91     }
    92     while (spfa()) {
    93         if (!mcf()) break;
    94     }
    95     printf("%d",Sf/2);
    96     return 0;
    97 }
  • 相关阅读:
    【Java-Web】初始化加载Serlvet工程后-HttpServlet报错
    【GIS】Cesium GLTF
    【视频】ffmpeg mov mp4 m3u8 ts
    【GIS】ArcGIS Server密码
    【NodeJS】http-server.cmd
    【GIS】Cesium回到初始位置
    【GIS】postgres(postgis) --》nodejs+express --》geojson --》leaflet
    深入浅出数据仓库中SQL性能优化之Hive篇
    大数据时代的技术hive:hive介绍
    hive优化之------控制hive任务中的map数和reduce数
  • 原文地址:https://www.cnblogs.com/mjtcn/p/8687412.html
Copyright © 2011-2022 走看看