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 n, m (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 ik, jk (1 ≤ ik < jk ≤ n, ik + jk is an odd number).
It is guaranteed that all the good pairs are distinct.
Output
Output the answer for the problem.
Example
3 2
8 3 8
1 2
2 3
0
3 2
8 12 8
1 2
2 3
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 }