• AC日记——[Sdoi2016]数字配对 bzoj 4514


    4514

    思路:

      很受伤现在,,测了那么多次不过的原因就是因为INF不够大;

      解法有两种:

        解法1:

          把n个点按照质因数个数为奇或偶分为两个点集(很容易就可以想到);

          然后,按照题目连边跑最大费用流;

          当累计的能量马上就要小于0时,退出循环,输出答案;

        解法2:

          把n个点拆成2*n个点,也是两个集合;

          如果ai[i]到ai[j]可以连边,则i连j+n,同时j连i+n;

          当累计的能量马上就要小于0时,退出循环,输出答案/2;

    来,上代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    #define ll long long
    #define INF 0x7ffffffffff
    
    ll n,prime[1000050],num_prime=0,ai[205],bi[205],ci[205];
    ll s,t,head[205],E[100005],V[100005],W[100005],F[100005];
    ll cnt=1,pre[205],que[200005],dis[205];
    
    bool if_prime[1000050],d1iv[205],if_[205];
    
    inline void in(ll &now)
    {
        ll if_z=1;now=0;
        char Cget=getchar();
        while(Cget>'9'||Cget<'0')
        {
            if(Cget=='-') if_z=-1;
            Cget=getchar();
        }
        while(Cget>='0'&&Cget<='9')
        {
            now=now*10+Cget-'0';
            Cget=getchar();
        }
        now*=if_z;
    }
    
    void euler(ll limit)
    {
        for(ll i=2;i<=limit;i++)
        {
            if(!if_prime[i]) prime[++num_prime]=i;
            for(ll j=1;prime[j]*i<=limit&&j<=num_prime;j++)
            {
                if_prime[i*prime[j]]=true;
                if(i%prime[j]==0) break;
            }
        }
    }
    
    inline bool cut(ll op)
    {
        ll res=0,now=0;
        while(op!=1&&now<10500)
        {
            now++;
            while(!(op%prime[now])) op/=prime[now],res++;
        }
        return res&1;
    }
    
    inline void edge_add(ll u,ll v,ll w,ll f)
    {
        E[++cnt]=head[u],head[u]=cnt,W[cnt]=w,F[cnt]=f,V[cnt]=v;
        E[++cnt]=head[v],head[v]=cnt,W[cnt]=-w,F[cnt]=0,V[cnt]=u;
    }
    
    inline bool spfa()
    {
        for(ll i=s;i<=t;i++) dis[i]=-INF,if_[i]=false,pre[i]=-1;
        ll h=0,tail=1;que[0]=s,if_[s]=true,dis[s]=0;
        while(h<tail)
        {
            ll now=que[h++];if_[now]=false;
            for(ll i=head[now];i;i=E[i])
            {
                if(F[i]>0&&dis[V[i]]<dis[now]+W[i])
                {
                    pre[V[i]]=i;
                    dis[V[i]]=dis[now]+W[i];
                    if(!if_[V[i]])
                    {
                        if_[V[i]]=true;
                        que[tail++]=V[i];
                    }
                }
            }
        }
        return dis[t]!=-INF;
    }
    
    int main()
    {
        in(n);euler(1000040),t=n+1;
        for(ll i=1;i<=n;i++) in(ai[i]);
        for(ll i=1;i<=n;i++) in(bi[i]);
        for(ll i=1;i<=n;i++) in(ci[i]);
        for(ll i=1;i<=n;i++)
        {
            if(cut(ai[i]))
            {
                d1iv[i]=true;
                edge_add(i,t,0,bi[i]);
            }
            else edge_add(s,i,0,bi[i]);
        }
        for(ll i=1;i<=n;i++)
        {
            if(!d1iv[i])
            {
                for(ll j=1;j<=n;j++)
                {
                    if(d1iv[j])
                    {
                        ll a=max(ai[i],ai[j]),b=min(ai[i],ai[j]);
                        if(a==b||a%b) continue;
                        if(!if_prime[a/b]) edge_add(i,j,ci[i]*ci[j],INF);
                    }
                }
            }
        }
        ll ans=0,cii=0;
        while(spfa())
        {
            ll now=t,pos=INF;
            while(pre[now]!=-1)
            {
                pos=min(pos,F[pre[now]]);
                now=V[pre[now]^1];
            }
            now=t;
            while(pre[now]!=-1)
            {
                F[pre[now]]-=pos;
                F[pre[now]^1]+=pos;
                now=V[pre[now]^1];
            }
            if(cii+dis[t]*pos<0)
            {
                ans+=cii/(-dis[t]);
                break;
            }
            ans+=pos,cii+=dis[t]*pos;
        }
        cout<<ans;
        return 0;
    }
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    #define maxn 205
    #define maxm 1000005
    #define ll long long
    #define INF 0x7ffffffffff
    
    ll que[maxm],E[maxm],V[maxm],F[maxm],W[maxm],cnt=1,bi[maxn];
    ll n,head[maxn<<1],s,t,dis[maxn<<1],pre[maxn<<1],ai[maxn],ci[maxn];
    
    bool if_[maxn<<1];
    
    inline void in(ll &now)
    {
        ll if_z=1;now=0;
        char Cget=getchar();
        while(Cget>'9'||Cget<'0')
        {
            if(Cget=='-') if_z=-1;
            Cget=getchar();
        }
        while(Cget>='0'&&Cget<='9')
        {
            now=now*10+Cget-'0';
            Cget=getchar();
        }
        now*=if_z;
    }
    
    inline void edge_add(ll u,ll v,ll w,ll f)
    {
        E[++cnt]=head[u],V[cnt]=v,W[cnt]=w,F[cnt]=f,head[u]=cnt;
        E[++cnt]=head[v],V[cnt]=u,W[cnt]=-w,F[cnt]=0,head[v]=cnt;
    }
    
    inline bool judge(ll op)
    {
        ll lit=sqrt(op);
        for(ll i=2;i<=lit;i++) if(!(op%i)) return false;
        return true;
    }
    
    inline bool spfa()
    {
        for(ll i=s;i<=t;i++) dis[i]=-INF,pre[i]=-1,if_[i]=false;
        ll h=0,tail=1;dis[s]=0,que[0]=s,if_[s]=true;
        while(h<tail)
        {
            ll now=que[h++];if_[now]=false;
            for(ll i=head[now];i;i=E[i])
            {
                if(F[i]>0&&dis[V[i]]<dis[now]+W[i])
                {
                    pre[V[i]]=i,dis[V[i]]=dis[now]+W[i];
                    if(!if_[V[i]]) if_[V[i]]=true,que[tail++]=V[i];
                }
            }
        }
        return dis[t]!=-INF;
    }
    
    int main()
    {
        freopen("menci_pair.in","r",stdin);
        freopen("menci_pair.out","w",stdout);
        in(n),t=n<<1|1;
        for(ll i=1;i<=n;i++) in(ai[i]);
        for(ll i=1;i<=n;i++)
        {
            in(bi[i]);
            edge_add(s,i,0,bi[i]);
            edge_add(i+n,t,0,bi[i]);
        }
        for(ll i=1;i<=n;i++) in(ci[i]);
        for(ll i=1;i<=n;i++)
        {
            for(ll j=1;j<=n;j++)
            {
                if(ai[i]<=ai[j]||ai[i]%ai[j]) continue;
                if(judge(ai[i]/ai[j]))
                {
                    edge_add(i,j+n,ci[i]*ci[j],INF);
                    edge_add(j,i+n,ci[i]*ci[j],INF);
                }
            }
        }
        ll ans=0,cii=0;
        while(spfa())
        {
            ll now=t,pos=INF;
            while(pre[now]!=-1)
            {
                pos=min(pos,F[pre[now]]);
                now=V[pre[now]^1];
            }
            now=t;
            while(pre[now]!=-1)
            {
                F[pre[now]]-=pos;
                F[pre[now]^1]+=pos;
                now=V[pre[now]^1];
            }
            if(cii+dis[t]*pos<0)
            {
                ans+=cii/abs(dis[t]);
                break;
            }
            ans+=pos,cii+=dis[t]*pos;
        }
        cout<<ans/2;
        return 0;
    }
  • 相关阅读:
    MySQL 锁的监控及处理
    mssql sqlserver 不固定行转列数据(动态列)
    SQL常用增删改查语句--来源于网络
    mssql sqlserver 对不同群组对象进行聚合计算的方法分享
    mssql sqlserver 自动备份存储过程的方法分享
    mssql sqlserver updatetext关键字应用简介说明
    mssql sqlserver 将字段null(空值)值替换为指定值的三种方法分享
    mssql sqlserver with cte表达式(递归)找出最顶值的方法分享
    mssql sqlserver text数据类型专题说明
    mssql sqlserver 使用sql脚本 清空所有数据库表数据的方法分享
  • 原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6756932.html
Copyright © 2020-2023  润新知