[SDOI2016]數字配對
Description
有 n 種數字,第 i 種數字是 ai、有 bi 個,權值是 ci。
若兩個數字 ai、aj 滿足,ai 是 aj 的倍數,且 ai/aj 是一個質數,
那麼這兩個數字可以配對,並獲得 ci×cj 的價值。
一個數字只能參與一次配對,可以不參與配對。
在獲得的價值總和不小於 0 的前提下,求最多進行多少次配對。
Input
第一行一個整數 n。
第二行 n 個整數 a1、a2、……、an。
第三行 n 個整數 b1、b2、……、bn。
第四行 n 個整數 c1、c2、……、cn。
Output
一行一個數,最多進行多少次配對
Sample Input
3
2 4 8
2 200 7
-1 -2 1
Sample Output
4
HINT
\(n\leqslant 200,a_i\leqslant 10^9,b_i\leqslant 10^5,|c_i|\leqslant 10^5\)
首先我們對\(a_i\)進行質因數分解,有\(a_i=\prod\limits_{i=1}^mp_i^{k_i}\),記\(d_i=\sum\limits_{i=1}^mk_i\),那麼兩個數\(i,j\)的配對條件,當且僅當\(a_j|a_i\)且\(d_i=d_j+1\)(\(a_i>a_j\)),於是我們對\(d_i\)的奇偶性進行分組,源點向所有\(d_i\)為奇數的點連一條流量為\(b_i\)
對於所有能匹配的\(i,j\),令\(d_i\)為奇數,則\(i\)向\(j\)連一條流量為\(\infty\),費用為\(c_i\times c_j\)的邊,然後跑最大費用最大流即可
由於要保證費用\(>0\)時流量最大,因此\(EK\)擴充套件的時候稍微有點不同,具體可以見程式碼
三年OI一場空,不開longlong見祖宗(我的1h啊)
/*program from Wolfycz*/ #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define inf 0x7f7f7f7f using namespace std; typedef long long ll; typedef unsigned int ui; typedef unsigned long long ull; inline char gc(){ static char buf[1000000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++; } inline int frd(){ int x=0,f=1; char ch=gc(); for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1; for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0'; return x*f; } inline int read(){ int x=0,f=1; char ch=getchar(); for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1; for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0'; return x*f; } inline void print(int x){ if (x<0) putchar('-'),x=-x; if (x>9) print(x/10); putchar(x%10+'0'); } const int N=2e2,M=2.1e4; int cnt[N+10],V[N+10],A[N+10]; int pre[M+10],now[N+10],child[M+10],val[M+10]; ll cost[M+10],dis[N+10],Maxcost; int flow[N+10],Line[N+10],Frm[N+10]; bool vis[N+10]; int n,S,T,Maxflow,tot=1; void join(int x,int y,int z,ll v){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z,cost[tot]=v;} void insert(int x,int y,int z,ll v){join(x,y,z,v),join(y,x,0,-v);} bool SPFA(){ static int h[N+10]; int head=0,tail=1; // memset(Frm,255,sizeof(Frm)); memset(dis,128,sizeof(dis)); memset(flow,127,sizeof(flow)); h[1]=S,vis[S]=1,dis[S]=0,Frm[T]=-1; while (head!=tail){ if (++head>N) head=1; int Now=h[head]; for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){ if (val[p]>0&&dis[son]<dis[Now]+cost[p]){ dis[son]=dis[Now]+cost[p]; Frm[son]=Now; Line[son]=p; flow[son]=min(flow[Now],val[p]); if (!vis[son]){ if (++tail>N) tail=1; vis[h[tail]=son]=1; } } } vis[Now]=0; } return Frm[T]!=-1; } void MCMF(){ while (SPFA()){ if (Maxcost+1ll*flow[T]*dis[T]<0){//注意直接退出 Maxflow+=(Maxcost/-dis[T]); break; } Maxflow+=flow[T]; Maxcost+=1ll*flow[T]*dis[T]; int Now=T; while (Now!=S){ val[Line[Now] ]-=flow[T]; val[Line[Now]^1]+=flow[T]; Now=Frm[Now]; } } } int main(){ n=read(),S=n+1,T=S+1; for (int i=1;i<=n;i++){ A[i]=read(); int x=A[i]; for (int j=2;j*j<=x;j++) while (x%j==0) x/=j,cnt[i]++; if (x!=1) cnt[i]++; } for (int i=1;i<=n;i++){ int y=read(); cnt[i]&1?insert(S,i,y,0):insert(i,T,y,0); } for (int i=1;i<=n;i++) V[i]=read(); for (int i=1;i<=n;i++) if (cnt[i]&1) for (int j=1;j<=n;j++) if (abs(cnt[i]-cnt[j])==1) if (A[i]%A[j]==0||A[j]%A[i]==0) insert(i,j,inf,1ll*V[i]*V[j]); MCMF(); printf("%d\n",Maxflow); return 0; }