题解
一开始看到这道题各种费用流的即视感。
首先这个配对应该可以想到构建二分图模型。构建出二分图后就比较容易把关系转化为边了。
但怎么构建呢?这个还是比较巧妙的,因为只有 小的数能整除大的数 且商为质数 的2个数才能配对。
也就是说只有在质因子个数相差1的情况下可能配对,于是很容易很把数分成2个集合。
然后在2个集合间靠关系建边。(具体怎么建就不阐述了)
另外在前提是跑最大费用最大流的情况下,由于整张图的流与当前费用最大的增广流之间存在单调性,
即随流变大,每次费用最大的增广流费用变小。(这个可以感性理解一下,主要是得意识到有这个性质)
所以我们一次次跑spfa,跑到最大费用不能再小为止。
答案就是最后的可行流。
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 typedef long long ll; 6 using namespace std; 7 const ll inf=1e18; 8 const int N=405; 9 const int M=100000; 10 int a[N],b[N],c[N],d[N]; 11 int n,cnt,x; 12 struct mcmf 13 { 14 int l,s,t,po,cnt; 15 int v[M],nxt[M],last[N],to[M],flow[N],pre_point[N],pre_edge[N],q[N+10]; 16 ll cost[M],f[N]; 17 bool flag[N]; 18 void clr() 19 { 20 l=1; 21 memset(last,0,sizeof(last)); 22 } 23 void ins(int x,int y,int z,ll c) 24 { 25 nxt[++l]=last[x]; 26 last[x]=l; 27 to[l]=y; 28 v[l]=z; 29 cost[l]=c; 30 } 31 void add(int x,int y,int z,ll c) 32 { 33 ins(x,y,z,c); 34 ins(y,x,0,-c); 35 } 36 bool spfa() 37 { 38 for (int i=0;i<=cnt;++i) 39 f[i]=-inf, 40 flag[i]=0, 41 flow[i]=0; 42 flow[s]=1e8; 43 f[s]=0; 44 q[1]=s; 45 int l,r,u,y; 46 l=0;r=1; 47 flag[s]=1; 48 while (l!=r) 49 { 50 l=l%N+1; 51 u=q[l]; 52 for (int x=last[u];x;x=nxt[x]) 53 if (v[x]) 54 { 55 y=to[x]; 56 if (f[u]+cost[x]>f[y]) 57 { 58 f[y]=f[u]+cost[x]; 59 flow[y]=min(flow[u],v[x]); 60 pre_point[y]=u; 61 pre_edge[y]=x; 62 if (flag[y]) continue; 63 flag[y]=1; 64 r=r%N+1; 65 q[r]=y; 66 } 67 } 68 flag[u]=0; 69 } 70 if (flow[t]) return 1; 71 else return 0; 72 } 73 int solve() 74 { 75 ll ans=0;int tot; 76 while (spfa()) 77 { 78 po=flow[t]; 79 if (ans+f[t]*flow[t]<0) 80 { 81 tot-=ans/f[t]; 82 ans+=ans/f[t]*f[t]; 83 break; 84 } 85 ans+=flow[t]*f[t]; 86 tot+=flow[t]; 87 for (int i=t;i!=s;i=pre_point[i]) 88 { 89 int e=pre_edge[i]; 90 v[e]-=po; 91 v[e^1]+=po; 92 } 93 } 94 return tot; 95 } 96 }T; 97 int main() 98 { 99 scanf("%d",&n); 100 T.clr(); 101 T.s=0; 102 for (int i=1;i<=n;++i) 103 { 104 scanf("%d",&x); 105 a[i]=x; 106 for (int j=2;j*j<=x;++j) 107 while (x%j==0) 108 ++d[i], 109 x/=j; 110 if (x>1) ++d[i]; 111 } 112 T.t=n+1; 113 T.cnt=n+1; 114 for (int i=1;i<=n;++i) scanf("%d",&b[i]); 115 for (int i=1;i<=n;++i) scanf("%d",&c[i]); 116 for (int i=1;i<=n;++i) 117 if (d[i]&1) T.add(T.s,i,b[i],0); 118 else T.add(i,T.t,b[i],0); 119 for (int i=1;i<=n;++i) 120 for (int j=1;j<=n;++j) 121 if (a[i]%a[j]==0 && d[i]==d[j]+1) 122 { 123 if (d[i]&1) T.add(i,j,1e8,(ll)c[i]*c[j]); 124 else T.add(j,i,1e8,(ll)c[i]*c[j]); 125 } 126 cout<<T.solve()<<endl; 127 return 0; 128 }