P4068 [SDOI2016] 数字配对
P4068 [SDOI2016] 数字配对
题目描述
有 \(n\) 种数字,第 \(i\) 种数字是 \(a_i\)、有 \(b_i\) 个,权值是 \(c_i\)。
若两个数字 \(a_i\)、\(a_j\) 满足,\(a_i\) 是 \(a_j\) 的倍数,且 \(a_i/a_j\) 是一个质数,
那么这两个数字可以配对,并获得 \(c_i \times c_j\) 的价值。
一个数字只能参与一次配对,可以不参与配对。
在获得的价值总和不小于 \(0\) 的前提下,求最多进行多少次配对。
输入格式
第一行一个整数 \(n\)。
第二行 \(n\) 个整数 \(a_1,a_2,\cdots,a_n\)。
第三行 \(n\) 个整数 \(b_1,b_2,\cdots,b_n\)。
第四行 \(n\) 个整数 \(c_1,c_2,\cdots,c_n\)。
输出格式
一行一个数,最多进行多少次配对。
说明/提示
\(6 \sim 10\): $n \leq 200 $, $a_i \leq 10 ^ 9 $ , \(b_i \leq 10 ^ 5\) ,$ | c_i | \leq 10 ^ 5$。
Solution:
我们先打一个 \([1,10^5]\) 的质数表,然后我们将每个 \(a_i\) 分解质因数。那么题目中的条件 "若两个数字 \(a_i\)、\(a_j\) 满足,\(a_i\) 是 \(a_j\) 的倍数,且 \(a_i/a_j\) 是一个质数" 的前半段是很好判定的,于是我们可以将后半段转化为 \(a_i,a_j\) 的质因数分解中有且仅有一位不同,且不同的那位的指数差值为 1 .
然后我们又发现 "\(a_i\) 是 \(a_j\) 的倍数" 这启示我们 \(\frac{a_i}{a_j}\) 这个数的质因数分解中有且仅有一位是 \(1\) 剩下的都是 \(0\),并且这个条件是充要的.所以我们可以直接统计 \(a_i\) 的质因数分解中为一位上指数的和 $ sum_i $.
形式化的:
\(a_i= \sum {P_j^{k_j}}\ \ ,\ \ sum_i=\sum k_j\)
那么我们的条件就等价于 \(sum_i-sum_j=1\)
然后我们就将这题的条件刻画出来了,不论是观察数据范围还是仔细思考一下都能快速联想到费用流。所以我们将其连边,对每个点 \(i\) 的连边即为:
\((S,i,b_i,0)\)
\((i,j,b_i,a_i\times a_j)\)
\((i,T,b_i,0)\)
边的四元组的意义是:
(起点,终点,流量,花费)
然后我们每次增广都希望将权值(费用)最大化,同时总权值(费用)不得小于0,需要注意一些细节。
然后这题就做完了。
Code:
(年幼时写的 \(O(n\sqrt{n})\) 暴力质数筛,但是懒得改了)
反正数据这么水
#include<bits/stdc++.h>
const long long N=50005;
const long long inf=1e17;
using namespace std;
long long n,m,zs_cnt,e_cnt=1,ans,sum;
long long zs[10005],head[N],dis[N],zs_num[N];
long long a[N],b[N],c[N],dl[N],flow[N],pre[N];
struct Edge{
long long to,nxt,flow,w;
}e[N<<2];
void add(long long x,long long y,long long flow,long long w)
{
e[++e_cnt]={y,head[x],flow,w};
head[x]=e_cnt;
}
bool check(long long x)
{
for(long long i=3;i<=sqrt(x);i+=2)
{
if(x%i==0)return 0;
}
return 1;
}
void zs_init()
{
long long idx=1e5;
zs[++zs_cnt]=2;
for(long long i=3;i<=idx;i+=2)
{
if(check(i))
{
zs[++zs_cnt]=i;
}
}
}
void change(long long x,long long id)
{
long long now=1;
while(x>1&&now<=zs_cnt)
{
if(x%zs[now]==0)
{
zs_num[id]++;
x/=zs[now];
}
else
{
now++;
}
}
if(now==zs_cnt+1&&x)
{
zs_num[id]=1;
return ;
}
return ;
}
void init()
{
for(long long i=0;i<=n+10;i++)
{
flow[i]=dl[i]=0;dis[i]=-inf;pre[i]=-1;
}
}
queue<long long> Q;
long long bj=0;
bool spfa(long long s,long long t)
{
init();
dis[s]=0;dl[s]=1;flow[s]=inf;
Q.push(s);
while(!Q.empty())
{
long long u=Q.front();dl[u]=0;Q.pop();
for(long long i=head[u];i;i=e[i].nxt)
{
long long v=e[i].to,w=e[i].w;
if((dis[v]<dis[u]+w)&&(e[i].flow>0))
{
dis[v]=dis[u]+w;pre[v]=i;
flow[v]=min(flow[u],e[i].flow);
if(!dl[v]){Q.push(v);dl[v]=1;}
}
}
}
return ~pre[n+1];
}
void solve()
{
long long ans=0,fl,now;
while(spfa(0,n+1))
{
if(ans+dis[n+1]<0)break;fl=flow[n+1];
if(dis[n+1]<0){fl=min(fl,ans/(-dis[n+1])); }
ans+=fl*dis[n+1],sum+=fl;now=n+1;
while(now!=0)
{
long long id=pre[now];long long u=e[id^1].to;
e[id].flow-=fl;e[id^1].flow+=fl;now=u;
}
}
printf("%lld",sum);
}
void work()
{
zs_init();
cin>>n;
for(long long i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
change(a[i],i);
}
for(long long i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
if(zs_num[i]&1)add(0,i,b[i],0),add(i,0,b[i],0);
else add(i,n+1,b[i],0),add(n+1,i,b[i],0);
}
for(long long i=1;i<=n;i++)
{
scanf("%lld",&c[i]);
}
for(long long i=1;i<=n;i++)
{
for(long long j=1;j<=n;j++)
{
if((a[i]%a[j]==0)&&abs((zs_num[i]-zs_num[j])==1))
{
long long x=i,y=j;
if(zs_num[j]&1)swap(x,y);
add(x,y,b[x],c[x]*c[y]);
add(y,x,0,-c[x]*c[y]);
}
}
}
solve();
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("num.out","w",stdout);
work();
return 0;
}

浙公网安备 33010602011771号