【BZOJ 4514】[Sdoi2016]数字配对 费用流
利用spfa流的性质,我直接拆两半,正解分奇偶(妙),而且判断是否整除且质数我用的是暴力根号,整洁判断质数个数差一(其他非spfa流怎么做?)
#include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N=205; const int P=N; const int E=N*N/2; const int Inf=0x3f3f3f3f; const LL oo=0xafafafafafafafafLL; struct V{ int to,next,f; LL c; }c[E]; int head[P],t=1; 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]=0,in[S]=true,q[back++]=S; if(back==P)back=0; while(front!=back){ int x=q[front++];in[x]=false; if(front==P)front=0; 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=0; } } } return dis[T]!=oo; } inline int shoot(){ int f=Inf; for(int i=anc[T];i;i=anc[c[i^1].to])f=std::min(f,c[i].f); for(int i=anc[T];i;i=anc[c[i^1].to])c[i].f-=f,c[i^1].f+=f; return f; } int main(){ scanf("%d",&n); S=n+1,T=S+1; for(int i=1;i<=n;++i){ scanf("%d",&key[i]); int x=key[i]; for(int j=2;j*j<=x;++j) while(x%j==0)++size[i],x/=j; if(x!=1)++size[i]; } for(int i=1;i<=n;++i){ scanf("%d",&cnt[i]); if(size[i]&1){ add(S,i,cnt[i],0); add(i,S,0,0); }else{ add(i,T,cnt[i],0); add(T,i,0,0); } } for(int i=1;i<=n;++i)scanf("%d",&val[i]); for(int i=1;i<=n;++i) if(size[i]&1) for(int j=1;j<=n;++j) if((size[j]&1)==0){ int x=key[i],y=key[j]; if(x>y)std::swap(x,y); if(y%x==0&&std::abs(size[i]-size[j])==1){ add(i,j,Inf,(LL)val[i]*val[j]); add(j,i,0,-(LL)val[i]*val[j]); } } while(spfa()){ int f=shoot(); if(f*dis[T]+ans<0){ for(int i=1;i<=f&&ans+dis[T]>=0;++i) ans+=dis[T],++sum; break; } ans+=f*dis[T]; sum+=f; } printf("%lld",sum); return 0; }
苟利国家生死以, 岂因祸福避趋之。