4514: [Sdoi2016]数字配对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1191 Solved: 446
[ Submit][ Status][ Discuss]
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
Source
题解:二分+费用流
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#define N 160003
#define M 203
#define LL long long
using namespace std;
const LL inf=1e18;
int a[M],b[M],c[M],n,pd[10000003],tot,ans;
int point[N],next[N],v[N],remain[N];
int point1[N],next1[N],v1[N],remain1[N];
LL val[N],val1[N],cost,dis[N];
int last[N],can[N],s,t,ck,prime[10000000];
void add(int x,int y,int z,LL k)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; val[tot]=k;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; val[tot]=-k;
// cout<<x<<" "<<y<<" "<<z<<" "<<k<<endl;
}
int addflow(int s,int t)
{
int now=t; int ans=1000000000;
while (now!=s) {
ans=min(ans,remain[last[now]]);
now=v[last[now]^1];
}
now=t;
while (now!=s) {
remain[last[now]]-=ans;
remain[last[now]^1]+=ans;
now=v[last[now]^1];
}
return ans;
}
bool spfa(int s,int t)
{
for (int i=1;i<=t;i++) dis[i]=-inf,can[i]=0;
dis[s]=0; can[s]=1;
queue<int> p; p.push(s);
//if (ans==6279443)
// printf("!\n");
while (!p.empty()) {
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=next[i])
if (dis[v[i]]<dis[now]+val[i]&&remain[i]) {
dis[v[i]]=dis[now]+val[i];
last[v[i]]=i;
if (!can[v[i]]) {
can[v[i]]=1;
p.push(v[i]);
}
}
can[now]=0;
}
if (dis[t]==-inf) return false;
int mx=addflow(s,t);
ans+=mx;
//cout<<dis[t]<<" "<<mx<<endl;
cost+=(LL)mx*(LL)dis[t];
//if (cost<0) return false;
return true;
}
bool check(int x)
{
ans=0; cost=0;
memcpy(point,point1,sizeof(point));
memcpy(next,next1,sizeof(next));
memcpy(v,v1,sizeof(v));
memcpy(remain,remain1,sizeof(remain));
memcpy(val,val1,sizeof(val));
remain[ck]=0; remain[ck^1]=x;
while (spfa(s,t));
//cout<<ans<<" "<<cost<<endl;
if (x==ans&&cost>=0) return true;
else return false;
}
void calc()
{
pd[0]=1; pd[1]=1;
for (int i=2;i<=10000000;i++) {
if (!pd[i]) {
prime[++prime[0]]=i;
}
for (int j=1;j<=prime[0];j++) {
if (prime[j]*i>10000000) break;
pd[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
}
bool pri(int x)
{
for (int i=2;i*i<=x;i++)
if (x%i==0) return false;
return true;
}
int main()
{
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
scanf("%d",&n); int sum=0;
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]),sum+=b[i];
for (int i=1;i<=n;i++) scanf("%d",&c[i]);
tot=-1;
memset(point,-1,sizeof(point));
calc();
s=1; t=n*2+2;
for (int i=1;i<=n;i++) {
add(s,i+1,b[i],0);
add(i+n+1,t,b[i],0);
for (int j=1;j<=n;j++)
if (i!=j&&a[i]%a[j]==0) {
int t=a[i]/a[j];
if (t<=10000000) {
if (!pd[t]) add(i+1,j+n+1,b[i],(LL)c[i]*(LL)c[j]),add(j+1,i+n+1,b[j],(LL)c[i]*(LL)c[j]);
//cout<<c[i]<<" "<<c[j]<<" "<<(LL)c[i]*(LL)c[j]<<endl;
continue;
}
if (pri(t)) add(i+1,j+n+1,b[i],(LL)c[i]*(LL)c[j]),add(j+1,i+n+1,b[j],(LL)c[i]*(LL)c[j]);
}
}
add(t,t+1,0,0);
t++;
ck=tot;
memcpy(point1,point,sizeof(point));
memcpy(next1,next,sizeof(next1));
memcpy(v1,v,sizeof(v1));
memcpy(remain1,remain,sizeof(remain));
memcpy(val1,val,sizeof(val));
int l=0; int r=sum; int ans=0;
while (l<=r) {
int mid=(l+r)/2;
// cout<<mid<<endl;
if (check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans/2);
}