To_Heart—题解——CF1473F

这里提供一种非常简单,而且贼有效的连边方式

首先因为靠后的点会被靠前的点限制,所以这是一道 最大闭合子图 的板题。

但是出题人卡了空间,当所有的 \(a_i\) 相同的时候,连边的复杂度是 \(n^2\) 的,会被卡掉。

我们考虑优化,因为 \(a_i \leq 100\) ,所以我们最多只需要连 100 条边就可以了,所以我们当 \(i\) 已经向 \(j\) 连边了,那么当 \(a_k=a_j,k\neq j\)的时候,我们就不需要由 \(i\)\(k\) 连边了。这个可以直接用桶来实现。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const int INF=0x3f3f3f3f;

struct zz{
	int u,w,id;
};
vector<zz> v[200005];
struct Dinic{
	int dist[200005],be[200005];
	int s,t;
	void Add(int x,int y,int z){
		int idx=v[x].size(),idy=v[y].size();
		v[x].push_back((zz){y,z,idy});
		v[y].push_back((zz){x,0,idx});
	}
	bool BFS(){
		bool f=0;memset(dist,-1,sizeof dist);
		queue<int> q;q.push(s);
		dist[s]=be[s]=0;
		while(!q.empty()){
			int x=q.front();q.pop();
			int siz=v[x].size();
			for(int i=0;i<siz;i++){
				int y=v[x][i].u,w=v[x][i].w;
				if(!w||dist[y]!=-1) continue;
				q.push(y),be[y]=0,dist[y]=dist[x]+1;
				if(y==t) f=1;
			}
		}
		return f;
	}
	int DFS(int x,int sum){
		if(x==t||!sum) return sum;
		int siz=v[x].size(),ans=0;
		for(int i=be[x];i<siz;i++){
			int y=v[x][i].u,w=v[x][i].w,id=v[x][i].id;be[x]=i;
			if(!w||dist[x]!=dist[y]-1) continue;
			int now=DFS(y,min(sum-ans,w));
			if(!now) dist[y]=0;
			v[x][i].w-=now,v[y][id].w+=now,ans+=now;
		}
		return ans;
	}
	int dinic(){
		int ans=0,now=0;
		while(BFS()) while(now=DFS(s,INF)) ans+=now;
		return ans;
	}
}T;
int n,sum=0;
int a[10005],b[10005];
bool f[3005];

vector<int> V[100005];

signed main(){
	cin>>n;T.s=0,T.t=n+1;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
	for(int i=1;i<=n;i++) {
		memset(f,0,sizeof f);
		for(int j=i-1;j>=1;j--){
			if(f[a[j]]) continue;
			if(a[i]%a[j]==0) T.Add(i,j,INF),f[a[j]]=1;
			
		}
	}
	for(int i=1;i<=n;i++){
		if(b[i]>=0) T.Add(T.s,i,b[i]),sum+=b[i];
		else T.Add(i,T.t,-b[i]);
	}
	printf("%lld\n",sum-T.dinic());
	return 0;
}
posted @ 2021-12-11 14:00  To_Heart  阅读(30)  评论(0编辑  收藏  举报