很好的题目.
主要的思路是,按照质因子个数的奇偶性对这些数字分成左右两组.
然后就在可以匹配的数字间连边,跑最长路费用流,一旦发现当前总价值要成为负值,结束费用流即可.
#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
",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
",maxflow);
return 0;
}