• BZOJ4514: [Sdoi2016]数字配对


    【传送门:BZOJ4514


    简要题意:

      给出n种数a[i]和每种数的个数b[i],再给出c[i](1<=i<=n),如果a[i]和a[j]能配对当且仅当a[i]%a[j]==0&&a[i]/a[j]为质数,并且i和j配对的价值为c[i]*c[j],要求在总价值不小于0的情况下,求出最大配对数


    题解:

      跟机房的Hanks_o和Rose_max讨论了老久才做出来

      最大费用最大流

      首先怎么处理两个数是否匹配呢,数据规模太大了,显然不能直接判质数或者用线性筛存素数

      我们发现,因为如果a[i]是a[j]的倍数,所以a[j]的质因数肯定在a[i]的质因数里面,那么只要a[i]的质因数减去a[j]的质因数为1时,证明a[i]/a[j]为质数

      就用f[i]表示a[i]的质因数个数,可以用O(n*a[i]0.5)做出来

      然后就是建边问题了,最初我们认为因为这并不是二分图,所以不能直接二分图转费用流

      但是我们发现,如果a[i]能与a[j]匹配,则i连向j+n(避免重复),流量为无穷大,费用为c[i]*c[j],这时,我们再把j连向i+n,流量为无穷大,费用为c[i]*c[j]

      为什么这么做?

      因为呢,我们在讨论的时候发现,一旦i选择走向j+n的话,j一定也会选择走向i+n

      那么就记录总流量,然后总流量/2就是答案了

      然而上面的做法会超时,因为流量太大了,普通的费用流(其实是我们平时用的费用流)是一流量一流量的流的,这样太慢了

      那么我们一旦找到一条增广路的时候就把这条增广路的流量榨干,注意,要判断总价值是否<0,如果总价值<0就退出费用流

      为什么这样做是正确的?因为当我们找到这条增广路的时候,这条增广路上的总价值一定是最大的(我们找的就是最大的),一旦这条增广路流不完,那么说明其他增广路也肯定不能流

      注意要加long long

      这次总结了一个经验:一个良好的代码习惯是最重要的(就因为平时没注意,结果硬生生WA了3次)


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<cstdlib>
    using namespace std;
    typedef long long LL;
    struct node
    {
        int x,y,c,next,other;
        LL d;
    }a[410000];int len,last[410];
    void ins(int x,int y,int c,LL d)
    {
        int k1=++len,k2=++len;
        a[k1].x=x;a[k1].y=y;a[k1].d=d;a[k1].c=c;
        a[k1].next=last[x];last[x]=k1;
        a[k2].x=y;a[k2].y=x;a[k2].d=-d;a[k2].c=0;
        a[k2].next=last[y];last[y]=k2;
        a[k1].other=k2;
        a[k2].other=k1;
    }
    LL d[410];int pre[410],pos[410];
    bool v[410];
    int list[410];
    int st,ed;
    bool spfa()
    {
        bool bk=false;
        memset(d,-63,sizeof(d));
        d[st]=0;
        memset(v,false,sizeof(v));
        v[st]=true;
        list[1]=st;
        int head=1,tail=2;
        while(head!=tail)
        {
            int x=list[head];
            for(int k=last[x];k;k=a[k].next)
            {
                int y=a[k].y;
                if(a[k].c>0&&d[y]<d[x]+a[k].d)
                {
                    d[y]=d[x]+a[k].d;
                    pos[y]=x;
                    pre[y]=k;
                    if(v[y]==false)
                    {
                        v[y]=true;
                        if(y==ed) bk=true;
                        list[tail++]=y;if(tail==ed+1)tail=1;
                    }
                }
            }
            head++;if(head==ed+1)head=1;
            v[x]=false;
        }
        return bk;
    }
    int f[210],A[210],B[210];
    LL c[210];
    int zys(int x)
    {
        int t=int(sqrt(double(x+1))),ans=0;
        for(int i=2;i<=t;i++)
        {
            while(x%i==0)
            {
                ans++;
                x/=i;
            }
        }
        if(x!=1) ans++;
        return ans;
    }
    LL ans,t;
    void Flow()
    {
        ans=0;
        while(spfa())
        {
            int x;
            int mc=999999999;
            for(x=ed;x!=st;x=pos[x]) mc=min(mc,a[pre[x]].c);
            if(d[ed]<0)
            {
                LL dd=abs(d[ed]);
                if(ans-LL(mc)*dd<0)
                {
                    t+=ans/dd;
                    break;
                }
            }
            ans+=mc*d[ed];
            t+=mc;
            for(x=ed;x!=st;x=pos[x])
            {
                a[pre[x]].c-=mc;
                a[a[pre[x]].other].c+=mc;
            }
        }
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        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("%lld",&c[i]);
        for(int i=1;i<=n;i++) f[i]=zys(A[i]);
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j) if(A[i]%A[j]==0&&f[i]-f[j]==1){ins(i,j+n,999999999,c[i]*c[j]);ins(j,i+n,999999999,c[i]*c[j]);}
        st=0;ed=n+n+1;
        for(int i=1;i<=n;i++)
        {
            ins(st,i,B[i],0LL);
            ins(i+n,ed,B[i],0LL);
        }
        t=0;Flow();
        printf("%lld
    ",t/2LL);
        return 0;
    }

     

  • 相关阅读:
    SpringBoot整合Flyway(数据库版本迁移工具)
    Java并发编程实战 05等待-通知机制和活跃性问题
    Java并发编程实战 04死锁了怎么办?
    Java并发编程实战 03互斥锁 解决原子性问题
    Java并发编程实战 02Java如何解决可见性和有序性问题
    Flutter学习笔记(40)--Timer实现短信验证码获取60s倒计时
    Flutter学习笔记(39)--BottomNavigationBar底部item超过3个只显示icon,不显示title
    Flutter学习笔记(38)--自定义控件之组合控件
    Flutter学习笔记(36)--常用内置动画
    Flutter学习笔记(37)--动画曲线Curves 效果
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8511342.html
Copyright © 2020-2023  润新知