【BZOJ4514】数字配对(费用流)

题意:

有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。

若两个数字 ai、aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数,

那么这两个数字可以配对,并获得 ci×cj 的价值。

一个数字只能参与一次配对,可以不参与配对。

在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

 n≤200,ai≤10^9,bi≤10^5,∣ci∣≤10^5

思路:裸的费用流,LYY一年前就已AC

加边的时候INT64没用,WA了好久……

费用流中每次找出的最长(短)路显然是依次不增(减)的,所以当找到一次不足以增广所有边时计算最多能增加的流量,且终止

  1 const oo=1<<60;
  2 var head,vet,next,q,a,b,c,flag,prime,fan,f:array[1..200000]of longint;
  3     pre:array[1..1000,1..2]of longint;
  4     inq:array[1..1000]of boolean;
  5     dis,len1,len2:array[1..200000]of int64;
  6     n,m,i,tot,j,x,source,src,s,t:longint;
  7     ans,flow,flow1:int64;
  8     p:boolean;
  9 
 10 function min(x,y:int64):int64;
 11 begin
 12  if x<y then exit(x);
 13  exit(y);
 14 end;
 15 
 16 function max(x,y:int64):int64;
 17 begin
 18  if x>y then exit(x);
 19  exit(y);
 20 end;
 21 
 22 procedure add(a,b:longint;c,d:int64);
 23 begin
 24  inc(tot);
 25  next[tot]:=head[a];
 26  vet[tot]:=b;
 27  len1[tot]:=c;
 28  len2[tot]:=d;
 29  head[a]:=tot;
 30 
 31  inc(tot);
 32  next[tot]:=head[b];
 33  vet[tot]:=a;
 34  len1[tot]:=0;
 35  len2[tot]:=-d;
 36  head[b]:=tot;
 37 end;
 38 
 39 function spfa:boolean;
 40 var u,e,v,i,t,w,t1,w1:longint;
 41 begin
 42  for i:=1 to s do
 43  begin
 44   dis[i]:=-oo;
 45   inq[i]:=false;
 46  end;
 47  t:=0; t1:=0; w:=1; w1:=1; dis[source]:=0; q[1]:=source; inq[source]:=true;
 48  while t<w do
 49  begin
 50   inc(t); inc(t1);
 51   if t1=1000 then t1:=1;
 52   u:=q[t1]; inq[u]:=false;
 53   e:=head[u];
 54   while e<>0 do
 55   begin
 56    v:=vet[e];
 57    if (len1[e]>0)and(dis[u]+len2[e]>dis[v]) then
 58    begin
 59     pre[v,1]:=u; pre[v,2]:=e;
 60     dis[v]:=dis[u]+len2[e];
 61     if not inq[v] then
 62     begin
 63      inc(w); inc(w1);
 64      if w1=1000 then w1:=1;
 65      q[w1]:=v; inq[v]:=true;
 66     end;
 67    end;
 68    e:=next[e];
 69   end;
 70  end;
 71  if dis[src]=-oo then exit(false);
 72  exit(true);
 73 end;
 74 
 75 procedure mcf;
 76 var k,e:longint;
 77     t,s,now,i:int64;
 78 begin
 79  t:=oo; k:=src; s:=0;
 80  while k<>source do
 81  begin
 82   e:=pre[k,2];
 83   t:=min(t,len1[e]);
 84   s:=s+len2[e];
 85   k:=pre[k,1];
 86  end;
 87 
 88  if ans+t*s<0 then
 89  begin
 90   p:=false;
 91   t:=ans div (-s);
 92  end;
 93  k:=src;
 94  while k<>source do
 95  begin
 96   e:=pre[k,2];
 97   len1[e]:=len1[e]-t;
 98   len1[fan[e]]:=len1[fan[e]]+t;
 99   k:=pre[k,1];
100  end;
101  ans:=ans+t*s;
102  flow:=flow+t;
103 
104 end;
105 
106 begin
107  assign(input,'bzoj4514.in'); reset(input);
108  assign(output,'bzoj4514.out'); rewrite(output);
109  readln(n);
110  for i:=1 to 200000 do
111   if i and 1=1 then fan[i]:=i+1
112    else fan[i]:=i-1;
113  for i:=1 to n do read(a[i]);
114  for i:=1 to n do read(b[i]);
115  for i:=1 to n do read(c[i]);
116  for i:=2 to 50000 do
117  begin
118   if flag[i]=0 then
119   begin
120    inc(m); prime[m]:=i;
121   end;
122   j:=1;
123   while (j<=m)and(prime[j]*i<=50000) do
124   begin
125    t:=prime[j]*i; flag[t]:=1;
126    if i mod prime[j]=0 then break;
127    inc(j);
128   end;
129  end;
130  for i:=1 to n do
131  begin
132   x:=a[i]; f[i]:=0;
133   j:=1;
134   while (x>1)and(j<=m) do
135   begin
136    while x mod prime[j]=0 do
137    begin
138     inc(f[i]);
139     x:=x div prime[j];
140    end;
141    inc(j);
142   end;
143   if x>1 then f[i]:=1;
144  end;
145  source:=n+1; src:=n+2; s:=n+2;
146  for i:=1 to n do
147   if f[i] and 1=1 then add(source,i,b[i],0)
148    else add(i,src,b[i],0);
149  for i:=1 to n do
150   for j:=1 to n do
151    if (f[i]=f[j]+1)and(a[i] mod a[j]=0) then
152    begin
153     if f[i] and 1=1 then add(i,j,maxlongint,int64(c[i])*c[j])
154      else add(j,i,maxlongint,int64(c[i])*c[j]);
155    end;
156  ans:=0; flow:=0; p:=true;
157  while spfa and p do mcf;
158  writeln(flow);
159  close(input);
160  close(output);
161 end.

 

posted on 2017-04-22 20:10  myx12345  阅读(132)  评论(0编辑  收藏  举报

导航