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
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
首先如果A[i]%A[j]==0且A[i]/A[j]是个质数,那么可以直接得出结论A[i]的质因子个数比A[j]的多1
有一种方法:枚举1~根号A[i],遇到能除的就除尽,那么这样子得出来的肯定是质因子个数(显而易见)
如果剩下来的不是1,那么铁定是一个质数
为什么??
因为你已经除到根号A[i]了,所以不会存在两个或以上大于根号A[i]的质数,否则就>A[i]了
因为你已经除到根号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