4514: [Sdoi2016]数字配对
生活随笔
收集整理的這篇文章主要介紹了
4514: [Sdoi2016]数字配对
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
有 n 種數字,第 i 種數字是 ai、有 bi 個,權值是 ci。
若兩個數字 ai、aj 滿足,ai 是 aj 的倍數,且 ai/aj 是一個質數,
那么這兩個數字可以配對,并獲得 ci×cj 的價值。
一個數字只能參與一次配對,可以不參與配對。
在獲得的價值總和不小于 0 的前提下,求最多進行多少次配對。
對于滿足條件的\(a_i/a_j\)一定要滿足\(a_i\)的質因子個數比\(a_j\)大一
所以可以對于每個數的質因子個數建二分圖,只有異側才有連邊
至于總價值不小于0,在總價值<0的時候停止就行了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#define M 1000001
#define LL long long
using namespace std;LL t,n,m,k,a[M],b[M],c[M],edge[M],nex[M],head[M],ver[M],cnt=1,h[M],d[M],cs[M],inq[M],cur[M],w[M],e[M],ed,zz,ans;
queue <LL> q;
void add(LL x,LL y,LL z,LL co)
{ver[++cnt]=y; nex[cnt]=head[x]; head[x]=cnt; edge[cnt]=z; cs[cnt]=co;ver[++cnt]=x; nex[cnt]=head[y]; head[y]=cnt; edge[cnt]=0; cs[cnt]=-co;
}bool spfa()
{memset(d,0,sizeof(d));memcpy(cur, head, sizeof(head));while(q.size()) q.pop();memset(h,-0x3f,sizeof(h));q.push(0); d[0]=1; h[0]=0; while(q.size()){LL x=q.front(); q.pop(); inq[x]=0;for(LL i=head[x];i;i=nex[i])if(edge[i] && h[ver[i]]<h[x]+cs[i]){h[ver[i]]=h[x]+cs[i]; d[ver[i]]=d[x]+1; if(!inq[ver[i]]) q.push(ver[i]);inq[ver[i]]=1;}}if(d[t]) return 1;return 0;
}LL dinic(LL x,LL flow)
{if(!flow || x==t) return flow;LL re=flow, k;for(LL & i=cur[x];i && re;i=nex[i])if(edge[i] && h[ver[i]]==h[x]+cs[i] && d[ver[i]]==d[x]+1){k=dinic(ver[i],min(re, edge[i]));re-=k; edge[i]-=k; edge[i^1]+=k;}return flow-re;
}LL fj(LL x)
{if(x==1) return 0;LL k=sqrt(x),ans=0; k+=1;for(LL i=2;i<=k;i++) if(x%i==0) while(x%i==0) x/=i,ans+=1;if(x!=1) ans+=1;return ans;
}int main()
{scanf("%lld",&n); t=n+1;for(LL i=1;i<=n;i++) scanf("%lld",&a[i]);for(LL i=1;i<=n;i++) scanf("%lld",&b[i]);for(LL i=1;i<=n;i++) scanf("%lld",&c[i]);for(LL i=1;i<=n;i++) w[i]=fj(a[i]);for(LL i=1;i<=n;i++) if(w[i]%2)for(LL j=1;j<=n;j++) if(w[j]%2==0 && ((a[i]%a[j]==0 && w[i]==w[j]+1)||(a[j]%a[i]==0 && w[j]==w[i]+1)))add(i,j,0x3f3f3f3f,c[i]*c[j]);for(LL i=1;i<=n;i++) if(w[i]%2) add(0,i,b[i],0);else add(i,t,b[i],0);while(spfa()){bool bll=1;while(k=dinic(0,0x3f3f3f3f)) {if(ed+h[t]*k<0) {ans+=ed/(-h[t]); bll=0; break;}ed+=h[t]*k, ans+=k;}if(!bll) break;}printf("%lld",ans);
}
轉載于:https://www.cnblogs.com/ZUTTER/p/10253589.html
總結
以上是生活随笔為你收集整理的4514: [Sdoi2016]数字配对的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一天一年是什么歌呢
- 下一篇: 安装需要的第三方库时,命令行输入pip提