• [SDOI2016 Round1] 数字配对


    COGS 2221. [SDOI2016 Round1] 数字配对

    http://www.cogs.pro/cogs/problem/problem.php?pid=2221

    ★★★   输入文件:menci_pair.in   输出文件:menci_pair.out   简单对比
    时间限制:1 s   内存限制:128 MB

    【题目描述】

    有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci

    若两个数字 aiaj 满足,ai 是 aj 的倍数,且 aiaj 是一个质数,那么这两个数字可以配对,并获得 ci×cj 的价值。

    一个数字只能参与一次配对,可以不参与配对。
    在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。

    【输入格式】

    第一行一个整数 n
    第二行 n 个整数 a1a2、……、an
    第三行 n 个整数 b1b2、……、bn
    第四行 n 个整数 c1c2、……、cn

    【输出格式】

    一行一个数,最多进行多少次配对。

    【样例输入】

    3

    2 4 8

    2 200 7

    -1 -2 1

    【样例输出】

    4

    【提示】

    测试点 1 ~ 3:n10ai109bi=1ci∣≤105
    测试点 4 ~ 5:n200ai109bi105ci=0
    测试点 6 ~ 10:n200ai109bi105ci∣≤105

    【来源】

    SDOI2016 Round1 Day1

    费用流u

    构图方法:(以样例为例)

    1、2可以配对;2、3可以配对

    注意,这里若a与b可以配对,则既要由a向b连边,又要由b向a连同样的边,最后答案除以2

    原因:

    1、如果只由a向b连,那么如果又有一条边由c连向a,边流量都为inf,这样从源点向a用了,由a向汇点又用了,应该统计的是2次之和,但实际只统计了其中一次

    2、a向b连边m、b向a连同样的边n,这样费用流跑m一定跑n,这样就可以把1中2次汇总,因为对应边流量相等,所以答案要除2

    因为要总价值和>=0,所以每次跑最大费用,

    如果本次跑出的最大价值+已累积的价值>=0,继续跑

    反之,次数+已累计价值/-本次单位流量最大费用,结束

    因为累计价值不可能为负,而题目要求总价值和>=0,若满足反之条件,本次最大费用<0 且 本次最大费用总和绝对值>已累计价值,所以就看已累计价值最大能抵消多少次本次的负价值

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<algorithm> 
    using namespace std;
    int a[201],b[201],c[201];
    int tot=1,src,dec;
    int front1[410],from[160001],next1[160001],to1[160001];
    bool v[410];
    int n,fa[410]; 
    long long dis[410],sum_cost,cost[160001],cap[160001];
    int sum_flow;
    queue<int>que;
    bool judge(int x)
    {
        for(int i=2;i<=sqrt(x);i++)
            if(x%i==0) return false;
        return true;
    }
    void insert_edge(int u,int v,long long w,long long val)
    {
        to1[++tot]=v;from[tot]=u;next1[tot]=front1[u];front1[u]=tot;cap[tot]=w;cost[tot]=val;
        to1[++tot]=u;from[tot]=v;next1[tot]=front1[v];front1[v]=tot;cap[tot]=0;cost[tot]=-val;
    }
    bool spfa()
    {
        for(int i=1;i<=dec;i++) dis[i]=-1e15,fa[i]=0;
        memset(v,0,sizeof(v));
        que.push(src);v[src]=true;
        dis[0]=0;
        while(!que.empty())
        {
            int now=que.front();
            que.pop();v[now]=false;
            for(int i=front1[now];i;i=next1[i])
            {
                if(dis[now]+cost[i]>dis[to1[i]]&&cap[i]>0)
                {
                    dis[to1[i]]=dis[now]+cost[i];
                    fa[to1[i]]=i;
                    if(!v[to1[i]])
                    {
                        que.push(to1[i]);
                        v[to1[i]]=true;
                    }
                }
            }
        }
        if(dis[dec]!=-1e10) return true;
        return false;
    }
    void work()
    {
        while(spfa()) 
        {
            long long tmp=1e15,k=0;
            for(int i=fa[dec];i;i=fa[from[i]]) tmp=min(cap[i],tmp);
            if(sum_cost+dis[dec]*1ll*tmp>=0)
            {
                sum_cost+=dis[dec]*tmp;sum_flow+=tmp;
                for(int i=fa[dec];i;i=fa[from[i]]) 
                {
                    cap[i]-=tmp;cap[i^1]+=tmp;
                }
            } 
            else
            {
                sum_flow+=int(sum_cost/abs(dis[dec]));
                break;
            }
        }
        printf("%d",sum_flow/2);
        return ;
    }
    int main()
    {
        freopen("menci_pair.in","r",stdin);
        freopen("menci_pair.out","w",stdout);
        scanf("%d",&n);
        dec=n+1<<1;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        for(int i=1;i<=n;i++) scanf("%d",&c[i]);
        for(int i=1;i<=n;i++) insert_edge(src,i<<1,b[i],0);
        for(int i=1;i<=n;i++) insert_edge(i<<1|1,dec,b[i],0);
        for(int i=1;i<=n;i++)
         for(int j=1;j<=n;j++)
          {
               if(a[i]<=a[j]) continue;
               if(a[i]%a[j]==0&&judge(a[i]/a[j]))
               {
                   insert_edge(j<<1,i<<1|1,1e15,1ll*c[i]*c[j]);
                  insert_edge(i<<1,j<<1|1,1e15,1ll*c[i]*c[j]);
             }
               
          }
        work();
    }

    学长说了另外2种方法:

    1、根据分解质因数的指数和的奇偶性,将所有点分为2个集合,构建二分图(标解,不想写就没写)

    学长AC代码链接:http://www.cnblogs.com/harden/p/6399396.html

    2、根据整除关系构成的链,将所有点分为2个集合,每条链的起点在哪个集合里随便,构建二分图,与1不同的地方就是链的起点在哪个集合的问题

    (这个写了,然而调了一晚上+半上午,COGS提交最终3A 1W 1RE 5T ,法2正确性、代码正确性有待验证)

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<algorithm> 
    using namespace std;
    int a[201],b[201],c[201];
    int front[210],next[160001],to[160001],tot,src,dec;
    int front1[210],from[160001],next1[160001],to1[160001];
    bool use_in[210],use_out[210],v[210];
    int n,fa[210]; 
    long long dis[210],sum_cost,cost[160001],cap[160001];
    int sum_flow;
    struct node1
    {
        int point,id;
    };
    queue<node1>q;
    queue<int>que;
    bool judge(int x)
    {
        for(int i=2;i<=sqrt(x);i++)
            if(x%i==0) return false;
        return true;
    }
    void add(int u,int v)
    {
        to[++tot]=v;next[tot]=front[u];front[u]=tot;
        use_in[v]=true;use_out[u]=true;
    }
    void insert_edge(int u,int v,long long w,long long val)
    {
        to1[++tot]=v;from[tot]=u;next1[tot]=front1[u];front1[u]=tot;cap[tot]=w;cost[tot]=val;
        to1[++tot]=u;from[tot]=v;next1[tot]=front1[v];front1[v]=tot;cap[tot]=0;cost[tot]=-val;
    }
    bool spfa()
    {
        for(int i=1;i<=dec;i++) dis[i]=-1e15,fa[i]=0;
        que.push(src);v[src]=true;
        while(!que.empty())
        {
            int now=que.front();
            que.pop();v[now]=false;
            for(int i=front1[now];i;i=next1[i])
            {
                if(dis[now]+1ll*cost[i]>dis[to1[i]]&&cap[i]>0)
                {
                    dis[to1[i]]=dis[now]+1ll*cost[i];
                    fa[to1[i]]=i;
                    if(!v[to1[i]])
                    {
                        que.push(to1[i]);
                        v[to1[i]]=true;
                    }
                }
            }
        }
        if(dis[dec]!=-1e15) return true;
        return false;
    }
    void work()
    {
        while(spfa()) 
        {
            long long tmp=1e15;
            for(int i=fa[dec];i;i=fa[from[i]]) tmp=min(cap[i],tmp);
            if(sum_cost+dis[dec]*1ll*tmp>=0)
            {
                sum_cost+=dis[dec]*tmp;sum_flow+=tmp;
                for(int i=fa[dec];i;i=fa[from[i]]) 
                {
                    cap[i]-=tmp;cap[i^1]+=tmp;
                }
            } 
            else
            {
                sum_flow+=int(sum_cost/abs(dis[dec]));
                break;
            }
        }
        printf("%d",sum_flow);
        return ;
    }
    int main()
    {
        freopen("menci_pair.in","r",stdin);
        freopen("menci_pair.out","w",stdout); 
        scanf("%d",&n);
        dec=n+1;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        for(int i=1;i<=n;i++) scanf("%d",&c[i]);
        for(int i=1;i<=n;i++)
         for(int j=1;j<=n;j++)
          {
               if(a[i]<=a[j]) continue;
               if(!a[j]) continue;
               if(a[i]%a[j]==0&&judge(a[i]/a[j]))
               {
                   add(j,i);
             }
          }
        tot=1;
        for(int i=1;i<=n;i++)
         if(!use_in[i])
         {
             insert_edge(src,i,b[i],0);
             q.push((node1){i,1});
         }
        while(!q.empty())
        {
            node1 now=q.front();q.pop();
            for(int i=front[now.point];i;i=next[i])
            {
                int t=to[i];
                if(now.id%2)
                {
                    insert_edge(now.point,t,1e15,1ll*c[now.point]*c[t]);
                    insert_edge(t,dec,b[t],0);
                    q.push((node1){t,now.id+1});
                }
                else
                {
                    insert_edge(t,now.point,1e15,1ll*c[now.point]*c[t]);
                    insert_edge(src,t,b[t],0);
                    q.push((node1){t,now.id+1});
                }
            }
        }
        work();
    }
    错误代码
  • 相关阅读:
    godep使用
    golang导入包的几个说明:import
    X-Frame-Options 响应头
    HTTP Strict Transport Security
    为什么我们要使用HTTP Strict Transport Security?
    IFrame安全问题解决办法(跨框架脚本(XFS)漏洞)
    基于iframe的CFS(Cross Frame Script)和Clickjacking(点击劫持)攻击
    javaWeb防止恶意登陆或防盗链的使用
    关于Cookie 的HttpOnly属性(java/web操作cookie+Tomcat操作jsessionid)
    会话cookie中缺少HttpOnly属性 解决
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6508988.html
Copyright © 2020-2023  润新知