[BZOJ4514] [SDOI2016] 数字配对 - 费用流

来源:互联网 发布:淘宝吊坠 编辑:程序博客网 时间:2024/05/29 19:43

显然可以根据质因子个数建二分图,再连源点和汇点,连边就可以跑费用流了。每次跑最大费用,直到费用小于0就结束过程,记录总流量即可 - -

#include"bits/stdc++.h"using namespace std;typedef long long ll; const int N=40005,M=50000;const int inf=(int)1e9;const ll llinf=(ll)1e18; int pri[M+5 >> 2],cnt,flag[M+5];void Linear_Shaker(){    for(int i=2;i<=M;i++){        if(!flag[i])pri[++cnt]=i;        for(int j=1;pri[j]*i<=M;j++){            flag[pri[j]*i]=1;            if(i%pri[j]==0)break;        }    }} int a[N],n,f[N],c[N],color[N],S,T;struct Edge {    int to;ll cost,flow;    Edge (int _=0,ll __=0,ll ___=0)    { to=_; flow=__; cost=___;}} e[N << 1];int head[N],next[N << 1],tmp=1; inline void addedge(int fr,int to,ll cost,int flow){    e[++tmp]=Edge(to,flow,cost);next[tmp]=head[fr];head[fr]=tmp;    e[++tmp]=Edge(fr,0,-cost);next[tmp]=head[to];head[to]=tmp;} int sep(int x){    int ans=0;if(x<2)return 0;    for(int i=1;pri[i]*pri[i]<=x;i++)        while(x%pri[i]==0)ans++,x/=pri[i];    return ans+(x>1);} void init(){    Linear_Shaker();    scanf("%d",&n);int i,j,s,t;S=0,T=n+1;    for(i=1;i<=n;i++)scanf("%d",&a[i]);    for(i=1;i<=n;i++)scanf("%d",&f[i]);    for(i=1;i<=n;i++)scanf("%d",&c[i]);    for(i=1;i<=n;i++)color[i]=sep(a[i]);    for(i=1;i<=n;i++)for(j=i+1;j<=n;j++){        s=i,t=j;if(a[i]<a[j])swap(s,t);        if(a[s]%a[t]==0&&color[s]==color[t]+1){            s=i,t=j;if(color[i]&1)swap(s,t);            addedge(s,t,(ll)c[i]*c[j],inf);        }    }    for(i=1;i<=n;i++)        if(color[i]&1)addedge(i,T,0,f[i]);        else addedge(S,i,0,f[i]);} int pre[N],q[N],l,r,inq[N],id[N];ll dist[N]; bool spfa(){    for(int i=S;i<=T;i++)dist[i]=-llinf,pre[i]=id[i]=0;    dist[S]=0;l=r=1;q[++r]=S;inq[S]=1;    while(l!=r){        l=(l+1)%(n+3);        int s=q[l];inq[s]=0;        for(int i=head[s];i;i=next[i]){            if(e[i].flow>0){                if(dist[s]+e[i].cost>dist[e[i].to]){                    dist[e[i].to]=dist[s]+e[i].cost;                    pre[e[i].to]=s;id[e[i].to]=i;                    if(!inq[e[i].to]){                        r=(r+1)%(n+3);                        q[r]=e[i].to;                        inq[e[i].to]=1;                    }                }            }        }    }    return pre[T]!=0;} void work(){    ll maxflow=0,i,flow,sumcost=0;    while(spfa()&&sumcost+dist[T]>=0){        flow=inf;        for(i=T;i;i=pre[i])            flow=min(flow,e[id[i]].flow);        if(sumcost+flow*dist[T]<0)            flow=sumcost/(-dist[T]);        for(i=T;i;i=pre[i]){            e[id[i]].flow-=flow;            e[id[i]^1].flow+=flow;        }        maxflow+=flow;        sumcost+=flow*dist[T];    }    printf("%lld\n",maxflow);} int main(){    init();work();    return 0;}


0 0
原创粉丝点击