1. 程式人生 > >BZOJ4514: [Sdoi2016]數字配對

BZOJ4514: [Sdoi2016]數字配對

AC ref 網絡 style != 進行 lan lld ()

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≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5

題目傳送門 毒瘤題。。。。 但說句公道話,這題很有意思,細節+想法巨多,在這裏感謝歐老師的傾力幫助 首先我們想一想怎麽連邊,200*200*根號10^9鐵定會炸 那該怎麽搞??
那麽就需要用到一個很好的想法:枚舉每個質因子(歐老師是我的紅太陽沒有他我就死。。。) 歐老師說:
首先如果A[i]%A[j]==0且A[i]/A[j]是個質數,那麽可以直接得出結論A[i]的質因子個數比A[j]的多1 有一種方法:枚舉1~根號A[i],遇到能除的就除盡,那麽這樣子得出來的肯定是質因子個數(顯而易見) 如果剩下來的不是1,那麽鐵定是一個質數 為什麽??
因為你已經除到根號A[i]了,所以不會存在兩個或以上大於根號A[i]的質數,否則就>A[i]了 那麽連邊之後就很好辦了,可是。。。我不會打有下界的網絡流 那我只能二分 可是如果強行清空的話又要超時。。。 所以還得memcpy 所有都得開long long (代碼顯得略醜) 代碼如下:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef 
long long ll; struct dicnic{ int x,y,next,other; ll d,c; }a[41000],e[41000]; int len,tlen,last[41000],first[41000]; const ll INF=1ll<<61; void inc(int x,int y,ll c,ll d) { int k1,k2; k1=++tlen; e[tlen].x=e[tlen].x=x;e[tlen].y=y;e[tlen].c=c;e[tlen].d=d; e[tlen].next=first[x];first[x]=tlen; k2=++tlen; e[tlen].x=y;e[tlen].y=x;e[tlen].c=0;e[tlen].d=-d; e[tlen].next=first[y];first[y]=tlen; e[k1].other=k2; e[k2].other=k1; } void ins(int x,int y,ll c,ll d) { int k1,k2; k1=++len; a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d; a[len].next=last[x];last[x]=len; k2=++len; a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1; } int st,ed; int pre[840],v[840]; ll d[840],cc[840]; int list[6*840],head,tail; ll ans,sum; bool spfa() { for(int i=1;i<=ed+1;i++)d[i]=-INF; d[st]=0; memset(v,false,sizeof(v));v[st]=true; memset(cc,0,sizeof(cc));cc[st]=INF; list[1]=st;head=1;tail=2; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&d[y]<d[x]+a[k].d) { d[y]=d[x]+a[k].d; pre[y]=k; cc[y]=min(cc[x],a[k].c); if(!v[y]) { v[y]=true; list[tail++]=y; if(tail==ed+1)tail=1; } } } head++;if(head==ed+1)head=1; v[x]=false; } if(d[ed]==-INF)return false; ans+=d[ed]*cc[ed];sum+=cc[ed]; int x=ed; while(x!=0) { int k=pre[x]; a[k].c-=cc[ed];a[a[k].other].c+=cc[ed]; x=a[k].x; } return true; } int n; ll A[210]; int f[210]; ll b[210],c[210]; bool check(ll x) { len=tlen; memcpy(last,first,sizeof(last)); memcpy(a,e,sizeof(a));ins(st,ed+1,x*2,0); ans=sum=0; while(spfa()==true) { } if(sum==x*2&&ans>=0)return true; return false; } int main() { ll xx=0;tlen=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld",&A[i]);int t=int(sqrt(double(A[i]+1)));ll x=A[i]; for(int j=2;j<=t;j++) { while(x%j==0) {x/=j;f[i]++;} }if(x!=1)f[i]++; } for(int i=1;i<=n;i++)scanf("%lld",&b[i]),xx+=b[i]; for(int i=1;i<=n;i++)scanf("%lld",&c[i]); ed=n*2+1;st=ed+1; for(int i=1;i<=n;i++) { inc(st,i,b[i],0);inc(i+n,ed,b[i],0); for(int j=1;j<=n;j++) if(A[i]%A[j]==0&&f[i]-f[j]==1) inc(i,j+n,INF,c[i]*c[j]),inc(j,i+n,INF,c[i]*c[j]); } st=ed+2; ll anss=0; ll l=0,r=xx*10; while(l<=r) { ll mid=(l+r)/2; if(check(mid)==true){l=mid+1,anss=mid;} else r=mid-1; } printf("%lld\n",anss); return 0; }

by_lmy

BZOJ4514: [Sdoi2016]數字配對