看到题目很容易发现是最大费用最大流。
关键点就是如何分成二分图。
(
QAQ
涨姿势了)
把每个
a
分解质因数:
记
Numi=∑x
那么可以发现可以根据
Numi
的奇偶性构造二分图。
然后正常建图。若
Numi
为奇数,连边
(S,i,bi,0)
,否则连边
(i,T,bi,0)
两个满足题意的点对
i,j
(不妨令
Numi
为奇数) 连边
(i,j,INF,−ci∗cj)
然后还有个问题就是要使总价值不小于0.
其实也好做。发现每次寻找到的一条增广路对应着取一对点,由于每次找最短路,一定是费用从大到小取(连得负边),那么每次判断一下,如果
当前费用+新增广路费用>=0
。就直接加入答案,否则判断一下该对点能取多少次,加入答案然后跳出。
【代码】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#define N 205
#define M 160405
#define Mod 1000000000
#define INF 1000000000000
using namespace std;
typedef long long ll;
typedef pair<int,ll> pa;
ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
pa ans;
int n,cnt,T;
int b[M],p[N],nextedge[M],w[M];ll c[M];
ll dis[N];int Pre[N];bool Flag[N];
int A[N],B[N],C[N],Num[N];
void Get_Num(int x)
{
int X=A[x];
for(int i=2;i*i<=X;i++) if(X%i==0) {
while(X%i==0)
X/=i,Num[x]++;
}
if(X>1) Num[x]++;
}
void Add(int x,int y,int z,ll cost) {
cnt++;
b[cnt]=y;
nextedge[cnt]=p[x];
p[x]=cnt;
w[cnt]=z;
c[cnt]=cost;
}
void Anode(int x,int y,int z,ll cost) {
Add(x,y,z,cost);Add(y,x,0,-cost);
}
bool Bfs()
{
queue<int>q;
q.push(0);
for(int i=1;i<=T;i++) dis[i]=INF;
while(!q.empty())
{
int k=q.front();q.pop();Flag[k]=0;
for(int i=p[k];i;i=nextedge[i])
{
int v=b[i],f=w[i];
if(dis[v]>dis[k]+c[i]&&f)
{
dis[v]=dis[k]+c[i];
Pre[v]=i;
if(!Flag[v])
{
Flag[v]=1;
q.push(v);
}
}
}
}
return dis[T]!=INF;
}
pa Mcf()
{
int Maxf=1000000000;ll rtn=0;
for(int i=Pre[T];i;i=Pre[b[i^1]])
Maxf=min(Maxf,w[i]);
for(int i=Pre[T];i;i=Pre[b[i^1]])
{
w[i]-=Maxf,w[i^1]+=Maxf;
rtn-=c[i]*Maxf;
}
return make_pair(Maxf,rtn);
}
int main()
{
n=read();T=n+1;cnt=1;
for(int i=1;i<=n;i++) A[i]=read(),Get_Num(i);
for(int i=1;i<=n;i++) B[i]=read();
for(int i=1;i<=n;i++) C[i]=read();
for(int i=1;i<=n;i++)
{
if(Num[i]&1) Anode(0,i,B[i],0);
else Anode(i,T,B[i],0);
if(Num[i]&1) {
for(int j=1;j<=n;j++)
if((Num[i]==Num[j]-1&&(A[j]%A[i]==0))||(Num[i]==Num[j]+1&&(A[i]%A[j]==0)))
Anode(i,j,1000000000,-1LL*C[i]*C[j]);
}
}
while(Bfs())
{
pa tmp=Mcf();
if(ans.second+tmp.second>=0)
ans.first+=tmp.first,ans.second+=tmp.second;
else {
ll cc=tmp.second/tmp.first;if(cc==0) break;
ans.first-=ans.second/cc;break;
}
}
printf("%d\n",ans.first);
return 0;
}