#Dinic,最大权闭合子图#CF1473F Strange Set
分析
对于这种依赖关系,可以将正权值连源点,负权值连汇点,
然后 \(i\) 向 \(j(j<i)\) 连无穷大的边,注意到如果完全建图空间不够,
考虑记录每个约数最后一次出现的位置,直接用 \(i\) 与 \(las\) 连边,这样边数为 \(12n\)
代码
#include <cstdio>
#include <cctype>
#include <queue>
using namespace std;
const int N=3011,inf=1e9;
struct node{int y,w,next;}e[N<<5];
int as[N],dis[N],n,S,T,et=1,ans,las[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void add(int x,int y,int w){
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,0,as[y]},as[y]=et;
}
bool bfs(int st){
for (int i=1;i<=T;++i) dis[i]=0;
queue<int>q; q.push(st),dis[st]=1;
while (!q.empty()){
int x=q.front(); q.pop();
for (int i=as[x];i;i=e[i].next)
if (e[i].w>0&&!dis[e[i].y]){
dis[e[i].y]=dis[x]+1;
if (e[i].y==T) return 1;
q.push(e[i].y);
}
}
return 0;
}
int min(int a,int b){return a<b?a:b;}
int dfs(int x,int now){
if (x==T||!now) return now;
int rest=0,f;
for (int i=as[x];i;i=e[i].next)
if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
f=dfs(e[i].y,min(now-rest,e[i].w)),
rest+=f,e[i].w-=f,e[i^1].w+=f;
if (now==rest) return now;
}
if (!rest) dis[x]=0;
return rest;
}
int main(){
n=iut(),S=n+1,T=S+1;
for (int i=1;i<=n;++i){
int x=iut();
for (int j=1;j*j<=x;++j)
if (x%j==0){
if (las[j]) add(i,las[j],inf);
if (j*j<x&&las[x/j]) add(i,las[x/j],inf);
}
las[x]=i;
}
for (int i=1;i<=n;++i){
int x=iut();
if (x>0) add(S,i,x),ans+=x;
else if (x<0) add(i,T,-x);
}
while (bfs(S)) ans-=dfs(S,inf);
return !printf("%d",ans);
}