#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);
}
posted @ 2022-02-16 10:37  lemondinosaur  阅读(29)  评论(0编辑  收藏  举报