zoukankan      html  css  js  c++  java
  • BZOJ4514: [Sdoi2016]数字配对(费用流)

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2197  Solved: 859
    [Submit][Status][Discuss]

    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

    Source

     
    啊啊啊啊啊费用流连边的时候把流量和费用搞混了调了两个小时QWQ
    考场上主要遇到了两个问题:
    1.如何保证费用大于0的时候流量最大
    2.如何保证每个点不被重复使用
    对于第一个问题,我们可以贪心解决
    即在增广的过程中,如果发现当前路径继续增光不满足条件,那么增广到上限后的最大流量就是答案
    对于第二个问题,我们可以把每个数质因数分解后,按照指数的奇偶分为左边和右边,这样连边的话就不会有重复了
     
    #include<bits/stdc++.h>
    #define int long long 
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
    using namespace std;
    const int MAXN=1e5+10;
    const int INF=1e16+10;
    char buf[1<<23],*p1=buf,*p2=buf;
    inline int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int N,S=0,T=23333;
    int A[MAXN],B[MAXN],C[MAXN],cnt[MAXN];
    struct node
    {
        int u,v,w,f,nxt;
    }edge[MAXN];
    int head[MAXN],num=0;
    
    inline void add_edge(int x,int y,int z,int f)
    {
        edge[num].u=x;
        edge[num].v=y;
        edge[num].w=z;
        edge[num].f=f;
        edge[num].nxt=head[x];
        head[x]=num++;
    }
    void AddEdge(int x,int y,int z,int f) 
    {
        add_edge(x,y,z,f);
        add_edge(y,x,-z,0);
    }
    inline int PrimeCut(int x)
    {
        int tot=0;
        for(int i=2;i<=sqrt(x);i++)
            while(x%i==0) x/=i,tot++;
        return x>1?tot+1:tot;
    }
    namespace Liu
    {
        int dis[MAXN],vis[MAXN],Pre[MAXN],ansflow=0,anscost=0;
        bool SPFA()
        {
            queue<int>q;
            q.push(S);
            memset(dis,0x3f,sizeof(dis));
            memset(vis,0,sizeof(vis));
            memset(Pre,0,sizeof(Pre));
            dis[S]=0;
            while(q.size()!=0)
            {
                int p=q.front();q.pop();
                vis[p]=0;
                for(int i=head[p];i!=-1;i=edge[i].nxt)
                {
                    if(edge[i].f>0&&dis[edge[i].v]>dis[p]+edge[i].w)
                    {
                        dis[edge[i].v]=dis[p]+edge[i].w;
                        Pre[edge[i].v]=i;
                        if(!vis[edge[i].v])
                            q.push(edge[i].v),
                            vis[edge[i].v]=1;
                    }
                }
            }
            return dis[T]<INF;
        }
        bool f()
        {
            int nowflow=INF;
            for(int i=T;i!=S;i=edge[Pre[i]].u)
                nowflow=min(nowflow,edge[Pre[i]].f);
            if(anscost+nowflow*(-dis[T]) < 0) 
            {
                ansflow+=anscost/dis[T];
                return 0;
            }
            for(int i=T;i!=S;i=edge[Pre[i]].u)
                edge[Pre[i]].f-=nowflow,
                edge[Pre[i]^1].f+=nowflow;
            anscost+=nowflow*(-dis[T]);
            ansflow+=nowflow;
        //    printf("%d
    ",ansflow);
            return 1; 
        }
        void MCMF()
        {
            bool flag=0;
            while(SPFA())
            {
                if( !f() )
                {
                    flag=1;
                    printf("%d",ansflow);
                    break;
                }
            }
            if(flag==0) printf("%d",ansflow);
        }
    }
    void Work()
    {
        for(int i=1;i<=N;i++) cnt[i]=PrimeCut(A[i]);
        for(int i=1;i<=N;i++)
            cnt[i]&1?AddEdge(S,i,0,B[i]):
                    AddEdge(i+N,T,0,B[i]);
        for(int i=1;i<=N;i++)
        {
            if(cnt[i]&1)
            {
                for(int j=1;j<=N;j++)
                    if( (cnt[i]+1==cnt[j]&&A[j]%A[i]==0) || (cnt[j]+1==cnt[i]&&A[i]%A[j]==0)  )
                        AddEdge(i,j+N,-C[i]*C[j],INF);    
            }
        }
        Liu::MCMF();
    }
    main()
    {
        #ifdef WIN32
        freopen("a.in","r",stdin);
        #else
        #endif
        memset(head,-1,sizeof(head));
        N=read();
        for(int i=1;i<=N;i++) A[i]=read();
        for(int i=1;i<=N;i++) B[i]=read();
        for(int i=1;i<=N;i++) C[i]=read();
        Work();
        return 0;
    }
  • 相关阅读:
    BZOJ 1800 [Ahoi2009]fly 飞行棋
    BZOJ 3309 DZY Loves Math
    CAS Server和client 实现单点登录
    单点登录原理与简单实现
    Maven插件
    win10安装最新nexus-3.x及maven简单配置介绍
    oracle获取表的属性,包括字段,注释
    java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一
    深入理解Tomcat虚拟目录
    环境搭建系列-系统安装之centos 6.5安装与配置
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8687391.html
Copyright © 2011-2022 走看看