BZOJ4514数字配对(费用流)

BZOJ4514数字配对(费用流)
题目链接
一开始思路是错的,直接把可以连边的Ai Aj连在一起了,然后就会产生某个数的汇聚流量<使用流量。我们按每个数的质因子个数建图,奇数个的建在左图,反之建立在右图。然后一个二分图产生了。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<queue>
#define N 300000
using namespace std;
const long long INF=-0x8f8f8f8f8f8f8f8fll;
int n,S,T;
long long ans;
int pri[31634],tot;
bool e[31634],pc[N];
int a[N],d[N];
long long b[N],c[N];
int fir[N],nes[N],v[N],top=1,bak[N],road[N];
long long q[N],w[N],f[N];
bool prime(int x)
{
    for(int i=1;i<=tot;i++)
        if(x==pri[i]) return true;
        else if(x%pri[i]==0) return false;

    return true;
}
void edge(int x,int y,long long z,long long p)
{
    top++;
    bak[top]=x; v[top]=y;
    q[top]=z; w[top]=p;
    nes[top]=fir[x];fir[x]=top;
    return;
}
#define edge(x,y,z,p) edge(x,y,z,p),edge(y,x,0,-p)
bool spfa()
{
    queue<int> V;
    memset(f,0x8f,sizeof(f));
    V.push(S); f[S]=0; pc[S]=true;
    while(!V.empty())
    {
        int c=V.front();
        for(int t=fir[c];t;t=nes[t])
        {
            if(!q[t] || f[v[t]]>=f[c]+w[t]) continue;
            f[v[t]]=f[c]+w[t]; road[v[t]]=t;
            if(pc[v[t]]) continue;
            V.push(v[t]); pc[v[t]]=true;
        }
        V.pop(); pc[c]=false;
    }
    return f[T]!=-INF;
}
void fly()
{
    long long cs=0;
    while(spfa())
    {
        long long c=INF;
        for(int t=T;t!=S;t=bak[road[t]]) c=min(c,q[road[t]]);
        if(f[T]*c+cs>=0) {ans+=c; cs+=f[T]*c;}
        else {ans+=cs/(-f[T]); break;}
        for(int t=T;t!=S;t=bak[road[t]])
        {
            q[road[t]]-=c;
            q[road[t]^1]+=c;
        }
    }
    return;
}
int main()
{
    scanf("%d",&n);
    S=n+1; T=S+1;
    for(int i=2;i<=31633;i++) if(!e[i])
        for(int j=i+i;j<=31633;j+=i) e[j]=true;
    for(int i=2;i<=31633;i++) if(!e[i]) pri[++tot]=i;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        int t=a[i],sum=0,radical=sqrt(a[i]);
        for(int j=1;j<=tot;j++)
        {
            while(t%pri[j]==0) sum++,t/=pri[j];
            if(t==1) break;
            if(pri[j]>radical) break;
        }
        if(t!=1) sum++;
        d[i]=sum%2;
    }
    for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
    for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
    for(int i=1;i<=n;i++)
    {
        if(d[i])  edge(S,i,b[i],0);
        else     {edge(i,T,b[i],0); continue;}
        for(int j=1;j<=n;j++)
        {
            if(d[j]) continue;
            int x=a[i],y=a[j];
            if(x<y) swap(x,y);
            if(x%y!=0) continue;
            if(prime(x/y)) edge(i,j,INF,c[i]*c[j]);
        }
    }
    fly();
    printf("%lld",ans);
    return 0;
}

上一篇:tab切换适用于H5和PC不借助组件


下一篇:thinkphp5数据的事务操作