codeforces #284 div2 E(最大流)
2014-12-25 13:00:32
思路:好题。
由于题目保证ik+jk为奇数,所以必然是一奇一偶,考虑a[ik],a[jk]相约,可知要先素数分解然后逐个消掉。
因为要求最大相约次数,考虑三种策略:贪心,DP,网络流。
一开始想贪心...画画图就否定掉了,DP?貌似也没啥思路。
正解是网络流,建立总源点,与每个偶数位置的数的素数因子相连,边的容量是因子的个数。建立总汇点,每个奇数位置的数的素数因子与之相连,容量为因子数。
然后根据m条i、j在偶数位置数和奇数位置数之间建边,流量为无穷。
然后跑一遍最大流即可。(PS:这种求最优解的问题要注意考虑到有网络流这一解法!)
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <set> 7 #include <map> 8 #include <queue> 9 #include <stack> 10 #include <algorithm> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned long long ull; 14 typedef pair<int,int> pii; 15 #define MP(a,b) make_pair(a,b) 16 const int maxv = 1000; 17 const int maxe = 1000; 18 const int INF = 1 << 30; 19 20 int n,m; 21 int sz[maxv]; 22 vector<pii> fac[maxv]; 23 24 struct Max_flow{ 25 int first[maxv],nxt[maxe],ver[maxe],cp[maxe],ecnt; 26 int lev[maxv],st,ed; 27 void Init(){ 28 memset(first,-1,sizeof(first)); 29 ecnt = 0; 30 } 31 void Add_edge(int u,int v,int c){ 32 nxt[ecnt] = first[u]; 33 ver[ecnt] = v,cp[ecnt] = c; 34 first[u] = ecnt++; 35 //opposite 36 nxt[ecnt] = first[v]; 37 ver[ecnt] = u,cp[ecnt] = 0; 38 first[v] = ecnt++; 39 } 40 bool Bfs(){ 41 queue<int> Q; 42 memset(lev,-1,sizeof(lev)); 43 Q.push(st); 44 lev[st] = 0; 45 while(!Q.empty()){ 46 int now = Q.front(); Q.pop(); 47 for(int i = first[now]; ~i; i = nxt[i]){ 48 int v = ver[i]; 49 if(lev[v] < 0 && cp[i] > 0){ 50 lev[v] = lev[now] + 1; 51 Q.push(v); 52 } 53 } 54 } 55 return lev[ed] != -1; 56 } 57 int Dfs(int p,int minf){ 58 if(p == ed) return minf; 59 for(int i = first[p]; ~i; i = nxt[i]){ 60 int v = ver[i]; 61 if(lev[v] > lev[p] && cp[i] > 0){ 62 int d = Dfs(v,min(cp[i],minf)); 63 if(d > 0){ 64 cp[i] -= d; 65 cp[i ^ 1] += d; 66 return d; 67 } 68 } 69 } 70 return 0; 71 } 72 int Dinic(){ 73 int max_flow = 0,plus; 74 while(Bfs()){ 75 while((plus = Dfs(st,INF)) > 0) 76 max_flow += plus; 77 } 78 return max_flow; 79 } 80 }; 81 82 83 int main(){ 84 int l,r,t1; 85 Max_flow MF; 86 MF.Init(); 87 scanf("%d%d",&n,&m); 88 for(int i = 1; i <= n; ++i){ 89 scanf("%d",&t1); 90 for(int j = 2; j * j <= t1; ++j) if(t1 % j == 0){ 91 int cnt = 0; 92 while(t1 % j == 0) t1 /= j,cnt++; 93 fac[i].push_back(MP(j,cnt)); 94 } 95 if(t1 > 1) fac[i].push_back(MP(t1,1)); 96 sz[i] = sz[i - 1] + fac[i].size(); 97 } 98 MF.st = sz[n] + 1; 99 MF.ed = sz[n] + 2; 100 for(int i = 1; i <= n; ++i){ 101 for(int j = 0; j < fac[i].size(); ++j){ 102 //if : even position , else : odd position 103 if(i % 2 == 0) MF.Add_edge(MF.st,sz[i - 1] + j,fac[i][j].second); 104 else MF.Add_edge(sz[i - 1] + j,MF.ed,fac[i][j].second); 105 } 106 } 107 for(int k = 1; k <= m; ++k){ 108 scanf("%d%d",&l,&r); 109 if(l % 2) swap(l,r); //two positions , the left is even and the right is odd 110 for(int i = 0; i < fac[l].size(); ++i){ 111 for(int j = 0; j < fac[r].size(); ++j){ 112 if(fac[l][i].first == fac[r][j].first) 113 MF.Add_edge(sz[l - 1] + i,sz[r - 1] + j,INF); 114 } 115 } 116 } 117 printf("%d\n",MF.Dinic()); 118 return 0; 119 }