[bzoj4514] [Sdoi2016]数字配对

 很好的题目.

 主要的思路是,按照质因子个数的奇偶性对这些数字分成左右两组.

 然后就在可以匹配的数字间连边,跑最长路费用流,一旦发现当前总价值要成为负值,结束费用流即可.

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iomanip>
using namespace std;
#define LL long long
#define up(i,j,n) for(LL i=j;i<=n;i++)
#define pii pair<LL,LL>
#define db double
#define eps 1e-10
#define FILE "dealing"
LL read(){
	LL x=0,f=1,ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();}
	return x*f;
}
const LL maxn=(LL)(1000000+3),inf=10000000000000000LL,limit=(LL)(6e5+0.1),mod=1000000007;
bool cmin(LL& a,LL b){return a>b?a=b,true:false;}
bool cmax(LL& a,LL b){return a<b?a=b,true:false;}
LL n,a[3000],b[3000],c[3000],prime[maxn],top=0,S,T;
namespace prepare{
	LL b[maxn],n=(LL)(1e6+1);
	void getprime(){
		for(LL i=2;i<=n;i++){
			if(!b[i])prime[++top]=i;
			for(LL j=1;prime[j]*i<=n&&j<=top;j++){
				b[i*prime[j]]=1;
				if(i%prime[j]==0)break;
			}
		}
	}
};
struct node{
	LL y,next,rev,v,flow;
}e[maxn];
LL len,linkk[maxn];
void insert(LL x,LL y,LL flow,LL v){
//	printf("%d %d %d %d\n",x,y,flow,v);
	e[++len].y=y;
	e[len].next=linkk[x];
	linkk[x]=len;
	e[len].rev=len+1;
	e[len].flow=flow;
	e[len].v=v;
	
	e[++len].y=x;
	e[len].next=linkk[y];
	linkk[y]=len;
	e[len].rev=len-1;
	e[len].flow=0;
	e[len].v=-v;
}
LL q[maxn<<2],head=0,ans=0,maxflow=0,vis[3000],tail=0,flow[3000],d[3000],R[3000],pre[3000];
bool SPFA(){
	memset(vis,0,sizeof(vis));
	up(i,S,T)d[i]=-inf;
	tail=head=0;
	q[++tail]=S;d[S]=0;
	flow[S]=inf;vis[S]=1;
	while(++head<=tail){
		LL x=q[head];vis[x]=0;
		for(LL i=linkk[x];i;i=e[i].next){
			if(e[i].flow&&d[e[i].y]<d[x]+e[i].v){
				d[e[i].y]=d[x]+e[i].v;
				if(!vis[e[i].y])q[++tail]=e[i].y,vis[e[i].y]=1;
				R[e[i].y]=i;
				pre[e[i].y]=x;
				flow[e[i].y]=min(flow[x],e[i].flow);
			}
		}
	}
	if(d[T]==-inf)return 0;
	if(ans+d[T]*flow[T]<0){
		maxflow+=(-ans)/(d[T]);
		return 0;
	}
	else ans+=d[T]*flow[T],maxflow+=flow[T];
	LL now=T;
	while(now){
		e[R[now]].flow-=flow[T];
		e[e[R[now]].rev].flow+=flow[T];
		now=pre[now];
	}
	return 1;
}
LL l[3000],r[3000],lcnt,rcnt;
bool check(LL x){
	if(x==1)return 0;
	for(LL i=1;prime[i]*prime[i]<x;i++){
		if(x%prime[i]==0)return 0;
	}
	return 1;
}
int main(){
	//freopen(FILE".in","r",stdin);
	//freopen(FILE".out","w",stdout);
	n=read();
	up(i,1,n)a[i]=read();
	up(i,1,n)b[i]=read();
	up(i,1,n)c[i]=read();
	prepare::getprime();
	up(i,1,n){
		LL y=a[i],cnt=0;
		up(j,1,top){
			if(y==1)break;
			while(y%prime[j]==0){
				y/=prime[j];
				cnt++;
			}
		}
		if(y!=1)cnt++;
		if(cnt%2)l[++lcnt]=i;
		else r[++rcnt]=i;
	}
	S=0,T=n+1;
	up(i,1,lcnt)insert(S,l[i],b[l[i]],0);
	up(i,1,rcnt)insert(r[i],T,b[r[i]],0);
	up(i,1,lcnt)up(j,1,rcnt){
		if(a[l[i]]%a[r[j]]==0&&check(a[l[i]]/a[r[j]]))
			insert(l[i],r[j],inf,c[l[i]]*c[r[j]]);
		if(a[r[j]]%a[l[i]]==0&&check(a[r[j]]/a[l[i]]))
			insert(l[i],r[j],inf,c[l[i]]*c[r[j]]);
	}
	while(SPFA());
	printf("%lld\n",maxflow);
	return 0;
}

  

posted @ 2017-03-08 12:49  CHADLZX  阅读(121)  评论(0编辑  收藏  举报