P4068 [SDOI2016]数字配对(隐含的二分图)

看到这题真是一头雾水

且不说要求费用>0的时候流最大

光是匹配就解决不了啊!!

k m \color{Red}不管是网络流还是km都只能解决二分图

所以要大胆相信这是个二分图

a i / a j = k ( k ) 因为匹配关系要求a_i/a_j=k(k为质数)

a i = k a j a_i=ka_j

a i a j a i a j 1 , k 1 ! ! 所以把a_i和a_j分解质因数发现a_i的指数和刚好比a_j大1,就大了k这个1!!

, 所以指数和是奇数的在二分图左边,指数和是偶数的在二分图右边

. 跑最大费用最大流即可.

等等…哪里不对?

最大费用小于0怎么办啊!!!

s p f a 广 , 广 所以在每次spfa找到增广路的时候,要知道这是当前费用最高的增广路

0 退 ( ) , 广 0 所以如果花费小于0了就退出(结算一下这次的流量),因为后续的增广路也小于0

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
const int inf=1e18;
struct edge{
	int to,nxt,flow,w;
}d[maxn]; int head[maxn],cnt=1,v[maxn];
void add(int u,int v,int w,int flow)
{
	d[++cnt]=(edge){v,head[u],flow,w},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],0,-w},head[v]=cnt;
}
int n,m,s,t,dis[maxn],vis[maxn],a[maxn],b[maxn],c[maxn],flow[maxn],pre[maxn];
bool spfa()
{
	for(int i=0;i<=t;i++)	dis[i]=-inf;
	queue<int>q; q.push(s);
	flow[s]=inf;dis[s]=0;
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v=d[i].to;
			if( d[i].flow&&dis[v]<dis[u]+d[i].w )
			{
				dis[v]=dis[u]+d[i].w;
				flow[v]=min( flow[u],d[i].flow );
				pre[v]=i;
				if( !vis[v] )	vis[v]=1,q.push(v);
			}
		}
	}
	return dis[t]!=-inf;
}
int fenjie(int x)
{
	int sqr=sqrt(x),tot=0;
	for(int i=2;i<=sqr;i++)	while( x%i==0 )	x/=i,tot++;
	if( x>1 )	tot++;
	return tot;
}
signed main()
{
	cin >> n;
	s=0,t=n+1;
	for(int i=1;i<=n;i++)	cin >> a[i];
	for(int i=1;i<=n;i++)	cin >> b[i];
	for(int i=1;i<=n;i++)	cin >> c[i];
	for(int i=1;i<=n;i++)	v[i]=fenjie(a[i]);
	for(int i=1;i<=n;i++)
	{
		if( v[i]&1 )	add(s,i,0,b[i]);
		else	add(i,t,0,b[i]);
	}
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		if( i==j )	continue;
		if( a[i]%a[j]==0&&v[i]==v[j]+1 )
		{
			if( v[i]&1 )	add(i,j,c[i]*c[j],inf);
			else	add(j,i,c[i]*c[j],inf);
		}
	}
	int maxcost=0,maxflow=0;
	while( spfa() )
	{
		if( maxcost+flow[t]*dis[t]>=0 )	maxcost+=flow[t]*dis[t];
		else
		{
			maxflow-=(maxcost/dis[t]);
			break;
		}
		maxflow+=flow[t];
		int x=t,i;
		while( x!=s )
		{
			i=pre[x];
			d[i].flow-=flow[t],d[i^1].flow+=flow[t];
			x=d[i^1].to;
		}
	}
	cout << maxflow;
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/108311567