• (最大流)CodeForces


    You have written on a piece of paper an array of n positive integers a[1], a[2], ..., a[n] and m good pairs of integers (i1, j1), (i2, j2), ..., (im, jm). Each good pair (ik, jk) meets the following conditions: ik + jk is an odd number and 1 ≤ ik < jk ≤ n.

    In one operation you can perform a sequence of actions:

    • take one of the good pairs (ik, jk) and some integer v (v > 1), which divides both numbers a[ik] and a[jk];
    • divide both numbers by v, i. e. perform the assignments:  and .

    Determine the maximum number of operations you can sequentially perform on the given array. Note that one pair may be used several times in the described operations.

    Input

    The first line contains two space-separated integers nm (2 ≤ n ≤ 100, 1 ≤ m ≤ 100).

    The second line contains n space-separated integers a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ 109) — the description of the array.

    The following m lines contain the description of good pairs. The k-th line contains two space-separated integers ikjk (1 ≤ ik < jk ≤ nik + jk is an odd number).

    It is guaranteed that all the good pairs are distinct.

    Output

    Output the answer for the problem.

    Example

    Input
    3 2
    8 3 8
    1 2
    2 3
    Output
    0
    Input
    3 2
    8 12 8
    1 2
    2 3
    Output
    2

    可以进行操作的两个数下标和为奇数,故必为一个下标奇数,一个下标偶数。建图时,对于每一对两个数,下标奇数的连向下标偶数的。除此之外再0连所有奇数下标,所有偶数下标连n+1。

    2个数进行操作显然每次取质数才能使得进行的操作次数最多,图中每条边记录两个数的同一质数幂次中的最小值。

    预处理得到小于等于1e5的所有质数,逐一建图,求最大流。进行过程中,将每个数的某质数幂次全部去掉。进行完毕时,每个数不是1就是一个大于1e5的质数。再进行最大流前的建图时,0和n+1连的点如果非1则该边容量为1,不然为0.其余每对数,如果两下标对应的数此时非1且相等,则边容量为1,否则为0.再进行一次最大流即可。

      1 #include <iostream>
      2 #include <string>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <queue>
      8 #include <set>
      9 #include <map>
     10 #include <list>
     11 #include <vector>
     12 #include <stack>
     13 #define mp make_pair
     14 //#define P make_pair
     15 #define MIN(a,b) (a>b?b:a)
     16 //#define MAX(a,b) (a>b?a:b)
     17 typedef long long ll;
     18 typedef unsigned long long ull;
     19 const int MAX=1e2+5;
     20 const int MAXN=1e5+5;
     21 const int maxn=205;
     22 const int INF=1e9+5;
     23 const ll INF2=4e18+5;
     24 const double M=4e18;
     25 using namespace std;
     26 const int MOD=1e9+7;
     27 typedef pair<ll,int> pii;
     28 const double eps=0.000000001;
     29 #define rank rankk
     30 
     31 /*
     32 Edmonds-Karp算法
     33 */
     34 struct Edge
     35 {
     36     int from,to,cap,flow;
     37     Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
     38 };
     39 struct EdmondsKarp
     40 {
     41     int n,m;
     42     vector<Edge>edges;//边数的两倍
     43     vector<int> G[maxn];//邻接表,G[i][j]表示结点i的第j条边在edges数组中的序号
     44     int a[maxn];//当起点到i的可改进量
     45     int p[maxn];//最短路树上p的入弧编号
     46     void init(int n)
     47     {
     48         for(int i=0;i<n;i++)
     49             G[i].clear();
     50         edges.clear();
     51     }
     52     void AddEdge(int from,int to,int cap)
     53     {
     54         edges.push_back(Edge(from,to,cap,0));
     55         edges.push_back(Edge(to,from,0,0));//反向弧
     56         m=edges.size();
     57         G[from].push_back(m-2);
     58         G[to].push_back(m-1);
     59     }
     60     int Maxflow(int s,int t)
     61     {
     62         int flow=0;
     63         for(;;)
     64         {
     65             memset(a,0,sizeof(a));
     66             queue<int>que;
     67             que.push(s);
     68             a[s]=INF;
     69             while(!que.empty())
     70             {
     71                 int x=que.front();que.pop();
     72                 for(int i=0;i<G[x].size();i++)
     73                 {
     74                     Edge &e=edges[G[x][i]];
     75                     if(!a[e.to]&&e.cap>e.flow)
     76                     {
     77                         p[e.to]=G[x][i];
     78                         a[e.to]=min(a[x],e.cap-e.flow);
     79                         que.push(e.to);
     80                     }
     81                 }
     82                 if(a[t])
     83                     break;
     84             }
     85             if(!a[t])
     86                 break;
     87             for(int u=t;u!=s;u=edges[p[u]].from)
     88             {
     89                 edges[p[u]].flow+=a[t];
     90                 edges[p[u]^1].flow-=a[t];
     91             }
     92             flow+=a[t];
     93         }
     94         return flow;
     95     }
     96 };
     97 EdmondsKarp notle;
     98 bool prime[MAXN];
     99 void getprime()
    100 {
    101     int da=1e5;
    102     memset(prime,true,sizeof(prime));
    103     prime[1]=false;
    104     for(int i=2;i<=da;i++)
    105     {
    106         if(prime[i])
    107         {
    108             for(int j=2;i*j<=da;j++)
    109                 prime[i*j]=false;
    110         }
    111     }
    112 }
    113 int getnum(int &x,int p)//x中p的幂次
    114 {
    115     int re=0;
    116     while(x%p==0)
    117     {
    118         x/=p;++re;
    119     }
    120     return re;
    121 }
    122 int n,m;
    123 int a[MAX];
    124 int x[MAX],y[MAX],an;
    125 int solve(int p)//质数p的情况
    126 {
    127     int num[MAX];
    128     memset(num,0,sizeof(num));
    129     notle.init(n+2);
    130     num[0]=num[n+1]=INF;
    131     for(int i=1;i<=n;i++)
    132         num[i]=getnum(a[i],p);
    133     for(int i=1;i<=n;i+=2)
    134         notle.AddEdge(0,i,num[i]);
    135     for(int i=2;i<=n;i+=2)
    136         notle.AddEdge(i,n+1,num[i]);
    137     for(int i=1;i<=m;i++)
    138     {
    139         if(x[i]%2==1)
    140             notle.AddEdge(x[i],y[i],min(num[x[i]],num[y[i]]));
    141         else
    142             notle.AddEdge(y[i],x[i],min(num[x[i]],num[y[i]]));
    143     }
    144     return notle.Maxflow(0,n+1);
    145 }
    146 int main()
    147 {
    148     scanf("%d%d",&n,&m);
    149     getprime();
    150     for(int i=1;i<=n;i++)
    151         scanf("%d",&a[i]);
    152     for(int i=1;i<=m;i++)
    153     {
    154         scanf("%d%d",&x[i],&y[i]);
    155     }
    156     for(int i=2;i<=1e5;i++)
    157     {
    158         if(prime[i])
    159             an+=solve(i);
    160     }
    161     notle.init(n+2);
    162     for(int i=1;i<=n;i+=2)
    163         notle.AddEdge(0,i,a[i]!=1?1:0);
    164     for(int i=2;i<=n;i+=2)
    165         notle.AddEdge(i,n+1,a[i]!=1?1:0);
    166     for(int i=1;i<=m;i++)
    167     {
    168         if(x[i]%2==1)
    169             notle.AddEdge(x[i],y[i],(a[x[i]]!=1&&a[x[i]]==a[y[i]])?1:0);
    170         else
    171             notle.AddEdge(y[i],x[i],(a[x[i]]!=1&&a[x[i]]==a[y[i]])?1:0);
    172     }
    173     an+=notle.Maxflow(0,n+1);
    174     printf("%d
    ",an);
    175 }
  • 相关阅读:
    Bellman算法
    Codeforces Round #378 (Div. 2) D
    运算符优先级
    Kruskal算法
    Java 大数运算
    无根树转有根树
    欧拉函数模板
    HDU 4135 Co-prime(容斥原理)
    快速求n的质因子(数论)
    Markdown中插入数学公式
  • 原文地址:https://www.cnblogs.com/quintessence/p/6946965.html
Copyright © 2020-2023  润新知