题意:
给定长度为n的序列和m个数对(ik,jk),
保证ik+jk是奇数,
一次操作你可以从m个数对里选一个,然后将Aik和Ajk同除以一个不等于1的公因数v,
问最多能执行多少次操作。
数据范围:n,m<=100,a(i)<=1e9
解法:
显然每次操作选择质因子操作数量最多
这种操作之间有交集的题,可以考虑用最大流计算最大操作次数
题目保证ik+jk是奇数,那么奇数位置和偶数位置可以作为二分图的两边
源点->偶数位置,边权inf
奇数位置->汇点,边权inf
偶数位置->这个偶数位置的的每种质因子(为每个质因子新建一个节点),边权为该质因子数量
每个奇数位置的每种质因子(为每个质因子新建一个节点)->他的奇数位置,边权为该质因子数量
m个数对中,数对之间相同质因子连接一条inf的边,方向为偶数质因子->奇数质因子
图大概是这样的:
其实位置点可以省略,源汇点直接连接每种质因子点也可以。
(省略掉位置点之后,容易看出建图模型其实就是二分图最大匹配)
ps:
最大流需要用到链式前向星编号的成对性质,边下标必须从偶数开始,
但是我平常习惯从1开始,连wa10多发才发现。。
所以说抄板子的时候init函数还是别偷懒不写。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
const int M=2e5+5;
const int inf=1e9;
//
int head[N],nt[M],to[M],w[M],cnt=1;
int d[N];
int st,ed;
int maxflow;
//
vector<pair<int,int> >fac[105];//<prime,id>
int idx;
//
int id[105];
int a[105];
int n,m;
//
void init(){
cnt=1;
}
void add(int x,int y,int z){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
}
bool bfs(){
queue<int>q;
q.push(st);
for(int i=2;i<=idx;i++)d[i]=0;
d[st]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(w[i]&&!d[v]){
d[v]=d[x]+1;
q.push(v);
if(v==ed)return 1;
}
}
}
return d[ed]!=0;
}
int dfs(int x,int flow){
if(x==ed)return flow;
int res=flow;
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(w[i]&&d[v]==d[x]+1){
int k=dfs(v,min(res,w[i]));
w[i]-=k;
w[i^1]+=k;
res-=k;
if(!k)d[v]=-1;
if(!res)break;
}
}
return flow-res;
}
void dinic(){
while(bfs()){
maxflow+=dfs(st,inf);
}
}
signed main(){
init();
cin>>n>>m;
//偶数位置作为左半部,奇数位置作为右半部
st=++idx,ed=++idx;
for(int i=1;i<=n;i++){
id[i]=++idx;
if(i%2==0){//源点->偶数位置
add(st,id[i],inf);
add(id[i],st,0);
}else{//奇数位置->汇点
add(id[i],ed,inf);
add(ed,id[i],0);
}
}
//
for(int i=1;i<=n;i++){
cin>>a[i];
int x=a[i];
for(int j=2;j*j<=x;j++){//
if(x%j==0){
int cnt=0;
while(x%j==0)x/=j,cnt++;
fac[i].push_back({j,++idx});
if(i%2==0){//偶数位置->质因子
add(id[i],idx,cnt);
add(idx,id[i],0);
}else{//质因子->奇数位置
add(idx,id[i],cnt);
add(id[i],idx,0);
}
}
}
if(x>1){
fac[i].push_back({x,++idx});
if(i%2==0){//偶数位置->质因子
add(id[i],idx,1);
add(idx,id[i],0);
}else{//质因子->奇数位置
add(idx,id[i],1);
add(id[i],idx,0);
}
}
}
for(int i=1;i<=m;i++){
int a,b;cin>>a>>b;
if(a%2)swap(a,b);//将a转换为偶数位置
int l=0,r=0;//双指针
while(l<fac[a].size()&&r<fac[b].size()){
int v1=fac[a][l].first;
int v2=fac[b][r].first;
int id1=fac[a][l].second;
int id2=fac[b][r].second;
if(v1==v2){//偶数位置的质因子->奇数位置的质因子
add(id1,id2,inf);
add(id2,id1,0);
l++,r++;
}else if(v1>v2){
r++;
}else if(v1<v2){
l++;
}
}
}
dinic();
cout<<maxflow<<endl;
return 0;
}