【BZOJ 4514】[Sdoi2016]数字配对 费用流

时间:2024-04-17 19:49:34

利用spfa流的性质,我直接拆两半,正解分奇偶(妙),而且判断是否整除且质数我用的是暴力根号,整洁判断质数个数差一(其他非spfa流怎么做?)

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=;
const int P=N;
const int E=N*N/;
const int Inf=0x3f3f3f3f;
const LL oo=0xafafafafafafafafLL;
struct V{
int to,next,f;
LL c;
}c[E];
int head[P],t=;
inline void add(int x,int y,int z,LL _){
c[++t].to=y,c[t].next=head[x],head[x]=t,c[t].f=z,c[t].c=_;
}
int n;
int key[N],cnt[N],val[N];
int S,T;
LL dis[P];
int anc[P];
int q[P],front,back;
bool in[P];
int size[N];
LL ans,sum;
inline bool spfa(){
memset(dis,0xaf,sizeof(dis));
dis[S]=,in[S]=true,q[back++]=S;
if(back==P)back=;
while(front!=back){
int x=q[front++];in[x]=false;
if(front==P)front=;
for(int i=head[x];i;i=c[i].next)
if(c[i].f&&dis[x]+c[i].c>dis[c[i].to]){
dis[c[i].to]=dis[x]+c[i].c,anc[c[i].to]=i;
if(!in[c[i].to]){
q[back++]=c[i].to,in[c[i].to]=true;
if(back==P)back=;
}
}
}
return dis[T]!=oo;
}
inline int shoot(){
int f=Inf;
for(int i=anc[T];i;i=anc[c[i^].to])f=std::min(f,c[i].f);
for(int i=anc[T];i;i=anc[c[i^].to])c[i].f-=f,c[i^].f+=f;
return f;
}
int main(){
scanf("%d",&n);
S=n+,T=S+;
for(int i=;i<=n;++i){
scanf("%d",&key[i]);
int x=key[i];
for(int j=;j*j<=x;++j)
while(x%j==)++size[i],x/=j;
if(x!=)++size[i];
}
for(int i=;i<=n;++i){
scanf("%d",&cnt[i]);
if(size[i]&){
add(S,i,cnt[i],);
add(i,S,,);
}else{
add(i,T,cnt[i],);
add(T,i,,);
}
}
for(int i=;i<=n;++i)scanf("%d",&val[i]);
for(int i=;i<=n;++i)
if(size[i]&)
for(int j=;j<=n;++j)
if((size[j]&)==){
int x=key[i],y=key[j];
if(x>y)std::swap(x,y);
if(y%x==&&std::abs(size[i]-size[j])==){
add(i,j,Inf,(LL)val[i]*val[j]);
add(j,i,,-(LL)val[i]*val[j]);
}
}
while(spfa()){
int f=shoot();
if(f*dis[T]+ans<){
for(int i=;i<=f&&ans+dis[T]>=;++i)
ans+=dis[T],++sum;
break;
}
ans+=f*dis[T];
sum+=f;
}
printf("%lld",sum);
return ;
}