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