cogs 2221. [SDOI2016 Round1] 数字配对
★★ 输入文件:pair.in 输出文件:pair.out 简单对比
时间限制:1 s 内存限制:128 MB
【题目描述】
有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。
若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,那么这两个数字可以配对,并获得 ci×cj 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。
【输入格式】
第一行一个整数 n。
第二行 n 个整数 a1、a2、……、an。
第三行 n 个整数 b1、b2、……、bn。
第四行 n 个整数 c1、c2、……、cn。
【输出格式】
一行一个数,最多进行多少次配对。
【样例输入】
3
2 4 8
2 200 7
-1 -2 1
【样例输出】
4
【提示】
测试点 1 ~ 3:n≤10,ai≤109,bi=1,∣ci∣≤105;
测试点 4 ~ 5:n≤200,ai≤109,bi≤105,ci=0;
测试点 6 ~ 10:n≤200,ai≤109,bi≤105,∣ci∣≤105。
题解:
首先看到让你求匹配,想到网络流中的二分图匹配,然而一个数字只能进行一次匹配,想了很长时间都不知道如何限流,如果直接判断能否匹配是无法确定流量的,正确做法如下:
X1/X2结果是质数,说明讲两个数分解质因数之后,X1的质因子比X2的质因子多1,其余质因子一样。所以X1,X2的质因子的个数的奇偶性不同。由此可以看到,将N个数分解质因数之后,因子数相同的两个数一定不会匹配,所以把数字按照质因子个数分成两个集合,就形成了二分图中的X集和Y集。
二分答案,用最大费用最大流来判断,如果流量等于二分的数值且最大费用大于等于0,则成立。
还有,这题数据范围较坑,inf=1e9还不够。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 using namespace std; 10 typedef long long LL; 11 const LL inf=1e15; 12 LL a[300],b[300],c[300],d[300],N,MAX; 13 LL prime[1000010],tot; 14 bool p[300][300]; 15 vector<LL> X,Y; 16 struct Edge{ 17 LL to,rest,next,cost; 18 }e[500000]; 19 LL head[300],cnt=1; 20 21 inline void addedge(LL x,LL y,LL r,LL z){ 22 e[++cnt].to=y; e[cnt].rest=r; e[cnt].cost= z; e[cnt].next=head[x]; head[x]=cnt; 23 e[++cnt].to=x; e[cnt].rest=0; e[cnt].cost=-z; e[cnt].next=head[y]; head[y]=cnt; 24 } 25 26 LL S,T,maxflow,mincost,dis[300],pre[300]; 27 bool vis[300]; 28 29 inline bool SPFA(){ 30 static queue<LL> Q; 31 while(!Q.empty()) Q.pop(); 32 for(LL i=0;i<=T;i++) dis[i]=-inf,vis[i]=false; 33 Q.push(S); dis[S]=0; vis[S]=true; 34 while(!Q.empty()){ 35 LL x=Q.front(); Q.pop(); vis[x]=false; 36 for(LL i=head[x];i;i=e[i].next){ 37 LL y=e[i].to; 38 if(e[i].rest>0&&(dis[y]<dis[x]+e[i].cost||dis[y]==-inf)){ 39 dis[y]=dis[x]+e[i].cost; 40 pre[y]=i; 41 if(vis[y]==false){ 42 vis[y]=true; 43 Q.push(y); 44 } 45 } 46 } 47 } 48 if(dis[T]>-inf) return true; 49 return false; 50 } 51 inline void update(){ 52 LL flow=inf; 53 for(LL i=pre[T];i;i=pre[e[i^1].to]) 54 flow=min(flow,e[i].rest); 55 for(LL i=pre[T];i;i=pre[e[i^1].to]){ 56 e[i].rest-=flow; 57 e[i^1].rest+=flow; 58 mincost+=flow*e[i].cost; 59 } 60 maxflow+=flow; 61 } 62 inline void ASK(){ 63 maxflow=0; mincost=0; 64 while(SPFA()) 65 update(); 66 } 67 inline bool jud(LL x){ 68 S=0; T=N+2; 69 for(LL i=0;i<=cnt+10;i++){ 70 e[i].cost=e[i].next=e[i].rest=e[i].to=0; 71 } 72 for(LL i=0;i<=N+20;i++) head[i]=0,pre[i]=0; 73 cnt=1; 74 for(LL i=0;i<X.size();i++){ 75 addedge(S,X[i],b[X[i]],0); 76 } 77 for(LL i=0;i<X.size();i++){ 78 for(LL j=0;j<Y.size();j++){ 79 if(p[X[i]][Y[j]]==true){ 80 addedge(X[i],Y[j],inf,c[X[i]]*c[Y[j]]); 81 } 82 } 83 } 84 for(LL i=0;i<Y.size();i++){ 85 addedge(Y[i],N+1,b[Y[i]],0); 86 } 87 addedge(N+1,T,x,0); 88 ASK(); 89 if(mincost>=0&&maxflow==x) return true; 90 return false; 91 } 92 inline LL find(LL l,LL r){ 93 if(l+1>=r){ 94 if(jud(r)==true) return r; 95 else return l; 96 } 97 LL mid=(l+r)>>1; 98 if(jud(mid)==true) return find(mid,r); 99 else return find(l,mid-1); 100 } 101 inline void shai(){ 102 for(LL i=1;i<=N;i++){ 103 for(LL j=1;j<=N;j++){ 104 if((a[i]>a[j])&&(a[i]%a[j]==0)){ 105 LL tmp=a[i]/a[j]; bool hhh=true; 106 for(LL k=2;k*k<=tmp&&k<=tmp;k++){ 107 if(tmp%k==0){ 108 hhh=false; break; 109 } 110 } 111 if(hhh==true){ 112 p[i][j]=p[j][i]=true; 113 // cout<<i<<" "<<j<<endl; 114 } 115 } 116 } 117 } 118 } 119 inline void calc(LL x){ 120 LL tmp=a[x]; 121 for(LL i=2;i*i<=tmp&&i<=tmp;i++){ 122 while(tmp%i==0){ 123 tmp/=i; 124 d[x]++; 125 } 126 } 127 if(tmp!=1) d[x]++; 128 } 129 int main(){ 130 scanf("%lld",&N); 131 for(LL i=1;i<=N;i++) scanf("%lld",&a[i]); 132 for(LL i=1;i<=N;i++) scanf("%lld",&b[i]),MAX+=b[i]; 133 for(LL i=1;i<=N;i++) scanf("%lld",&c[i]); 134 shai(); 135 for(LL i=1;i<=N;i++) calc(i); 136 for(LL i=1;i<=N;i++){ 137 if(d[i]%2==1) X.push_back(i); 138 else Y.push_back(i); 139 } 140 printf("%lld",find(0,inf)); 141 return 0; 142 }