【题解】CF498C Array and Operations
题面传送门
前置芝士
最大流。推销安利我的博客:网络流:最大流最小割
解决思路
首先考虑,要同时除以一个公约数,而且要操作次数最多,所以每次除以的要是公共质因数。
同时,对于每对数都满足
所以网络流的模型就浮现出来了。我们对于每一个出现过的质因数建一张图。设源点为
-
对于所有下标为奇数的数
,从 向 连一条容量为 的边。 -
对于所有下标为偶数的数
,从 向 连一条容量为 的边。 -
对于所有数对
,钦定 为奇数,从 向 连一条容量为 的边,意为选 最多可以删这么多次。
然后,从源点到汇点的最大流就是整个数列中可以删除
所以可以把最大流封装一下,对于每一个质因数跑一遍最大流,把答案加起来就好了。
具体细节可以看代码,其中
AC Code
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
#define inf 1e16
#define qwq cout<<"qwq"<<endl
using namespace std;
int n,m,a[20005];
int u,v,cntt,Ans;
map<int,int> mp,id;
struct MaxFlow{ //dinic最大流板子
int tot=1,head[2005],cur[2005],dep[2005]; //封装的话数组、变量要定义在里面(
struct node{
int to,nxt,f;
}e[2005];
void add(int u,int v,int f){
e[++tot]={v,head[u],f},head[u]=tot;
e[++tot]={u,head[v],0},head[v]=tot;
}
queue<int> q;
int bfs(int s,int t){
while(q.size()) q.pop();q.push(s);
memset(dep,0,sizeof(dep));dep[s]=1;
while(q.size()){
int x=q.front();q.pop();
for(int i=head[x];i;i=e[i].nxt){
node tmp=e[i];
if(tmp.f&&!dep[tmp.to]){
dep[tmp.to]=dep[x]+1;
q.push(tmp.to);
}
}
}
return dep[t];
}
int dfs(int s,int t,int f){
if(s==t||!f) return f;
int ans=0;
for(int i=cur[s];i;i=e[i].nxt){
node &x=e[i];cur[s]=i;
if(x.f&&dep[x.to]==dep[s]+1){
int tmp=dfs(x.to,t,min(f,x.f));
x.f-=tmp,e[i^1].f+=tmp;
ans+=tmp,f-=tmp;
if(f<=0) break;
}
}
return ans;
}
int dinic(int s,int t){
int ans=0;
while(bfs(s,t)){
memcpy(cur,head,sizeof(head));
ans+=dfs(s,t,inf);
}
return ans;
}
}mf[205];
void build(int i,int j){ //连接数对
int ans=0,t1=a[i],t2=a[j];
mp.clear();
for(int i=2;i*i<=t1;i++){
while(t1%i==0) t1/=i,mp[i]++;
}
if(t1>1) mp[t1]++; //对其中一个分解质因数
for(auto k:mp){
int tmp=t2,cnt=0;
while(cnt<k.se&&tmp%k.fi==0) tmp/=k.fi,cnt++; //容量取min
if(cnt) mf[id[k.fi]].add(i,j,cnt);
}
}
void calc(int z,int x,int op){ //连接源点、汇点
mp.clear();
for(int i=2;i*i<=x;i++){
while(x%i==0) x/=i,mp[i]++;
}
if(x>1) mp[x]++; //分解质因数
for(auto k:mp){
if(!id[k.fi]) id[k.fi]=++cntt;
if(!op) mf[id[k.fi]].add(0,z,k.se); //奇数下标连源点
else mf[id[k.fi]].add(z,n+1,k.se); //偶数下标连汇点
}
}
signed main(){
IOS;TIE;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
if(i&1) calc(i,a[i],0);
else calc(i,a[i],1);
}
for(int i=1;i<=m;i++){
cin>>u>>v;
if(v&1) swap(u,v); //保证第一个下标是奇数
build(u,v);
}
for(auto i:id) Ans+=mf[i.se].dinic(0,n+1); //所有质因数最大流之和
cout<<Ans<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话