您的位置:首页 > 其它

bzoj4514 [Sdoi2016]数字配对

2017-12-28 15:49 441 查看
(http://www.elijahqi.win/2017/12/28/bzoj4514-sdoi2016%E6%95%B0%E5%AD%97%E9%85%8D%E5%AF%B9/)

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

这题 还是一个 要是看出 以分解质因数之后质因数的个数的奇偶性来划分的话 就是板子题了

可惜我看不出qwq

确实 因为 我只有一种可能就是我质因数个数 奇数和偶数才可以构成答案 所以不妨我把质因数个数位奇数的放在左边 偶数的放在右边 然后每个点 连容量位b[i]的点去源或者汇 然后如果这两个数 满足条件的话 则连上他们中间的c数组相乘作为费用的边 跑最大费用流即可 注意判断是否是质数的时候我一开始以为我既然都求出了not_prime这个数组了 那就直接用吧 不行,显然是错的啊 我有可能数超过了1e5 就gg了 所以还是循环一下 看能否分解质因数判断是否是质数 注意本题long long十分重要

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 440000
#define N 22000
#define inf 1LL<<60
#define ll long long
using namespace std;
inline char gc(){
static char now[1<<16],*T,*S;
if (T==S) {T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
return x*f;
}
int tot,prime[110000],q1[220],q2[220],tot1,tot2,T,h[220],flag[220];ll f[220];
bool not_prime[110000];int path[220],pre[220],num=1,n,a[220],b[220],c[220];
struct node{
int x,y,z,next;ll c;
}data[55000];
inline void insert1(int x,int y,int z,ll c){
data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num;data[num].c=c;data[num].x=x;
data[++num].y=x;data[num].z=0;data[num].next=h[y];h[y]=num;data[num].c=-c;data[num].x=y;
}
inline bool spfa(){
for (int i=0;i<=n+1;++i) f[i]=-inf;
memset(flag,0,sizeof(flag));queue<int>q;q.push(0);memset(pre,-1,sizeof(pre));f[0]=0;flag[0]=1;
while(!q.empty()){
int x=q.front();q.pop();flag[x]=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;ll c=data[i].c;
if (f[x]+c>f[y]&&z){
f[y]=f[x]+c;pre[y]=x;path[y]=i;
if (!flag[y]) flag[y]=1,q.push(y);
}
}
}if (pre[T]==-1) return 0;else return 1;
}
inline bool judge(int i,int j){
if (!a[i]||!a[j]||a[i]%a[j]&&a[j]%a[i]) return 0;
int dis=max(a[j]/a[i],a[i]/a[j]);
for (int i=1;i<=tot;++i)
if (prime[i]>=dis) break;else if (dis%prime[i]==0)return 0;return 1;
}
int main(){
freopen("bzoj4514.in","r",stdin);
n=read();for (int i=1;i<=n;++i) a[i]=read();T=n+1;not_prime[0]=1;not_prime[1]=1;
for (int i=1;i<=n;++i) b[i]=read();for (int i=1;i<=n;++i) c[i]=read();
for (int i=2;i<=1e5;++i){
if (!not_prime[i]) prime[++tot]=i;
for (int j=1;prime[j]*i<=1e5;++j) {
not_prime[prime[j]*i]=1;if (i%prime[j]==0) break;
}
}
for (int i=1;i<=n;++i){
int sum=0,now=a[i];
for (int j=1;j<=tot;++j){
while(now%prime[j]==0) sum++,now/=prime[j];if (now==1) break;
}
if (sum%2) q1[++tot1]=i;else q2[++tot2]=i;
}
for (int i=1;i<=tot1;++i)
for (int j=1;j<=tot2;++j)
if (judge(q1[i],q2[j])) insert1(q1[i],q2[j],0x3f3f3f3f,(ll)c[q1[i]]*c[q2[j]]);
for (int i=1;i<=tot1;++i) insert1(0,q1[i],b[q1[i]],0);ll ans1=0;
for (int i=1;i<=tot2;++i) insert1(q2[i],T,b[q2[i]],0);int ans=0;
//for (int i=2;i<=num;++i) printf("%d %d %d %d\n",data[i].x,data[i].y,data[i].z,data[i].c);
while(spfa()){
int minn=0x3f3f3f3f,now=T;ll tmp=0;
while(now) minn=min(minn,data[path[now]].z),now=pre[now];now=T;
while(now) {tmp+=data[path[now]].c;data[path[now]].z-=minn;data[path[now]^1].z+=minn;now=pre[now];}
if (ans1+tmp*minn<0){
ans-=ans1/tmp;break;
}else ans+=minn,ans1+=tmp*minn;
} printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: