给n个数, m个数对, 每个数对是两个下标加起来为奇数的两个数。每次操作可以使一个数对中的两个数同时除某个数, 除的这个数是这两个数的任意约数, 问这种操作最多可以做几次。n<100, m<100。
这个数据范围, 以及下标加起来为奇数...好明显的网络流暗示。
首先对每个数分解, 看它含有哪些素因子, 每个素因子的个数是多少, 因为只有100个数, 所以素因子的总数不是很多。
然后枚举每个素因子。对每个数对中的两个数连边, 如果下标是奇数, 源点就向这个数连边, 下标是偶数, 这个数向汇点连边。 权值为这个数含有这个素因子的个数。
然后跑很多遍网络流, 答案就是所有结果相加。
具体可以看代码
1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <cmath> 7 #include <map> 8 #include <set> 9 #include <string> 10 #include <queue> 11 #include <stack> 12 #include <bitset> 13 using namespace std; 14 #define pb(x) push_back(x) 15 #define ll long long 16 #define mk(x, y) make_pair(x, y) 17 #define lson l, m, rt<<1 18 #define mem(a) memset(a, 0, sizeof(a)) 19 #define rson m+1, r, rt<<1|1 20 #define mem1(a) memset(a, -1, sizeof(a)) 21 #define mem2(a) memset(a, 0x3f, sizeof(a)) 22 #define rep(i, n, a) for(int i = a; i<n; i++) 23 #define fi first 24 #define se second 25 typedef pair<int, int> pll; 26 const double PI = acos(-1.0); 27 const double eps = 1e-8; 28 const int mod = 1e9+7; 29 const int inf = 1061109567; 30 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; 31 map <int, int> mp[105], ma; 32 pll b[105]; 33 const int maxn = 2e4; 34 int q[maxn*2], head[maxn*2], dis[maxn/10], s, t, num; 35 int vis[105]; 36 struct node 37 { 38 int to, nextt, c; 39 node(){} 40 node(int to, int nextt, int c):to(to), nextt(nextt), c(c){} 41 }e[maxn*2]; 42 void init() { 43 num = 0; 44 mem1(head); 45 mem(vis); 46 } 47 void add(int u, int v, int c) { 48 e[num] = node(v, head[u], c); head[u] = num++; 49 e[num] = node(u, head[v], 0); head[v] = num++; 50 } 51 int bfs() { 52 mem(dis); 53 dis[s] = 1; 54 int st = 0, ed = 0; 55 q[ed++] = s; 56 while(st<ed) { 57 int u = q[st++]; 58 for(int i = head[u]; ~i; i = e[i].nextt) { 59 int v = e[i].to; 60 if(!dis[v]&&e[i].c) { 61 dis[v] = dis[u]+1; 62 if(v == t) 63 return 1; 64 q[ed++] = v; 65 } 66 } 67 } 68 return 0; 69 } 70 int dfs(int u, int limit) { 71 if(u == t) { 72 return limit; 73 } 74 int cost = 0; 75 for(int i = head[u]; ~i; i = e[i].nextt) { 76 int v = e[i].to; 77 if(e[i].c&&dis[v] == dis[u]+1) { 78 int tmp = dfs(v, min(limit-cost, e[i].c)); 79 if(tmp>0) { 80 e[i].c -= tmp; 81 e[i^1].c += tmp; 82 cost += tmp; 83 if(cost == limit) 84 break; 85 } else { 86 dis[v] = -1; 87 } 88 } 89 } 90 return cost; 91 } 92 int dinic() { 93 int ans = 0; 94 while(bfs()) { 95 ans += dfs(s, inf); 96 } 97 return ans; 98 } 99 int main() 100 { 101 int n, m, x; 102 cin>>n>>m; 103 for(int i = 0; i<n; i++) { 104 scanf("%d", &x); 105 for(int j = 2; j*j<=x; j++) { 106 if(x%j==0) { 107 mp[i][j] = 0; //mp是看第i个数含有素数j的个数 108 ma[j] = 1; //ma是存储这n个数所有的素因子 109 } 110 while(x%j==0) { 111 x/=j; 112 mp[i][j]++; 113 } 114 } 115 if(x>1) { 116 mp[i][x] = 1; 117 ma[x] = 1; 118 } 119 } 120 for(int i = 0; i<m; i++) { 121 cin>>b[i].fi>>b[i].se; 122 b[i].fi--, b[i].se--; 123 } 124 auto it = ma.begin(); 125 int ans = 0; 126 while(it != ma.end()) { 127 int pri = it->first; //枚举所有素因子 128 init(); 129 s = n+1, t = n+2; 130 for(int i = 0; i<m; i++) { 131 if(b[i].fi%2==1) { 132 add(b[i].fi, b[i].se, inf); 133 if(!vis[b[i].fi]) { 134 add(s, b[i].fi, mp[b[i].fi][pri]); //如果这个数之前没出现过, 那么就向源点或者汇点连边。 135 vis[b[i].fi] = 1; 136 } 137 if(!vis[b[i].se]) { 138 add(b[i].se, t, mp[b[i].se][pri]); 139 vis[b[i].se] = 1; 140 } 141 } else { 142 add(b[i].se, b[i].fi, inf); 143 if(!vis[b[i].fi]) { 144 add(b[i].fi, t, mp[b[i].fi][pri]); 145 vis[b[i].fi] = 1; 146 } 147 if(!vis[b[i].se]) { 148 add(s, b[i].se, mp[b[i].se][pri]); 149 vis[b[i].se] = 1; 150 } 151 } 152 } 153 int tmp = dinic(); 154 ans += tmp; 155 it++; 156 } 157 cout<<ans<<endl; 158 159 }