标签:codeforces 网络流
传送门:cf 498C
给定一个长度为n的数组,已经m组下标对应关系(下标之和为奇数),现在可以对m组对应关系中的数同除一个大于1的整数,问最多能进行多少次这样的操作
要操作次数最大,每次处理的时候应该除质数。
下标之和为奇数,不难发现它构成了一张二分图。
枚举sqrt(10^9)的质数,找出n个数中各有多少个这样的质数k,然后建立对应的图,跑网络流最大流即可。
/****************************************************** * File Name: c.cpp * Author: kojimai * Create Time: 2014年12月25日 星期四 01时05分10秒 ******************************************************/ #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<iostream> using namespace std; bool prime[32333]; int a[105],x[105],y[105],e; int n,m,len[105],first[105],next[2333]; struct Edge { int x,y,f,next; }edge[2333]; void addedge(int x,int y) { edge[e].x = x;edge[e].y = y;edge[e].next = first[x];edge[e].f = min(len[x],len[y]);first[x] = e++;//每条边的流量为相连两点中含质数个数的较小值 edge[e].x = y;edge[e].y = x;edge[e].next = first[y];edge[e].f = 0;first[y] = e++; } void init() { memset(prime,false,sizeof(prime)); for(int i = 2;i <= 31622;i++) { if(!prime[i]) { for(int j = i + i;j <= 31622;j += i) prime[j] = true; } } e = 0; return; } int dis[105]; bool bfs(int s,int t) { memset(dis,-1,sizeof(dis)); dis[s] = 0; queue<int> p; p.push(s); while(!p.empty()) { int now = p.front();p.pop(); //cout<<" now = "<<now<<endl; for(int k = first[now];k != -1;k = edge[k].next) { if(edge[k].f && dis[edge[k].y] == -1) { dis[edge[k].y] = dis[now] + 1; if(edge[k].y == t) return true; p.push(edge[k].y); } } } return false; } int dfs(int now,int flow,int t) { int f; if(now == t) return flow; for(int k = first[now];k != -1;k = edge[k].next) { if(edge[k].f && dis[edge[k].y] == dis[now] + 1 && (f = dfs(edge[k].y,min(flow,edge[k].f),t))) { edge[k].f -= f; edge[k^1].f += f; return f; } } return 0; } int dinic(int s,int t) { int flow,ret = 0; while(bfs(s,t)) { while(flow = dfs(s,23333333,t)) ret += flow; } return ret; } int solve(int xx) {//处理只除以质数xx的情况下的最大操作次数 memset(len,0,sizeof(len)); for(int i = 1;i <= n;i++) { while(a[i] % xx == 0) { len[i]++;//找出每个数中有多少个质数xx a[i] /= xx; } } len[0] = len[n+1] =23333; e = 0; memset(first,-1,sizeof(first)); for(int i = 1;i <= m;i++) { if(x[i] % 2 == 1) addedge(x[i],y[i]); else addedge(y[i],x[i]); } for(int i = 1;i <= n;i+= 2) addedge(0,i); for(int i = 2;i <= n;i+= 2) addedge(i,n+1); int ret = dinic(0,n+1); return ret; } void adde(int x,int y) { edge[e].x = x;edge[e].y = y;edge[e].next = first[x]; if(x == 0) edge[e].f = 1; else if(y == n+1) edge[e].f = 1; else if(a[x] == a[y] && a[x] > 1)//当处理较大质数时,因为所有较小质数都已经处理过了,只要两数相等就是同样大的质数,且只能除一次 edge[e].f = 1; else edge[e].f = 0; first[x] = e++; edge[e].x = y;edge[e].y = x;edge[e].next = first[y];edge[e].f = 0;first[y] = e++; } int main() { init(); scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); } for(int i = 1;i <= m;i++) { scanf("%d%d",&x[i],&y[i]); } int ans = 0; for(int i = 2;i <= 31622;i++) { if(!prime[i]) ans += solve(i); } for(int i = 1;i <= n;i+= 2) adde(0,i); for(int i = 2;i <= n;i+= 2) adde(i,n+1); for(int i = 1;i <= m;i++) { if(x[i] % 2 == 1) adde(x[i],y[i]); else adde(y[i],x[i]); } ans += dinic(0,n+1);//处理剩下当质数大于sqrt(10^9)时的情况 cout << ans <<endl; return 0; }
codeforces 498C Array and Operations 网络流
标签:codeforces 网络流
原文地址:http://blog.csdn.net/u010535824/article/details/42141933