Luogu P4068 [SDOI2016]数字配对

反正现在做题那么少就争取做一题写一题博客吧

看到题目发现数字种类不多,而且结合价值的要求可以容易地想到使用费用流

但是我们如果朴素地建图就会遇到一个问题,若\(i,j\)符合要求,那么给\(i,j\)连的应该是双向边,但双向边怎么跑网络流?

所以我们就要考虑怎么给边定向,我们稍加观察就会发现如果\(i,j\)合法,\(j,k\)也合法,那么\(i,k\)显然是不合法的(分四类情况讨论一下都是不合法的)

考虑那个整除出一个质数的条件,我们发现如果我们定义\(ct_i\)为\(a_i\)的所有质因数的指数之和

那么\(i,j\)满足条件当且仅当\((ct_i=ct_j+1\and a_j|a_i)\or(ct_j=ct_i+1\and a_i|a_j)\),这样一来我们就可以解释上面\(i,j,k\)三者的关系了

那么我们发现在有了\(ct_i\)之后我们就可以把数字分在两边,左边放奇数,右边放偶数,这样就构成了一个二分图,我们只从左边向右边连边即可

然后注意一下我们用EK跑最小费用最大流时每一次增广求出的最长路一定不会大于上一次增广求出的最长路,因此直接按顺序累加即可,注意最后一次的特判,详见代码

#include<cstdio>
#include<queue>
#include<iostream>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=205,INF=1e18;
struct edge
{
    int to,nxt,v,c;
}e[N*N<<2]; int n,head[N],s,t,cnt=1,a[N],b[N],c[N],ct[N];
inline int resolve(int x,int ret=0)
{
    for (RI i=2;i*i<=x;++i) while (x%i==0) ++ret,x/=i; return ret+(x>1);
}
class Network_Flow
{
    private:
        queue <int> q; int dis[N],pre[N],lst[N],cap[N]; bool vis[N];
        #define to e[i].to
        inline bool SPFA(CI s,CI t)
        {
            RI i; for (i=s;i<=t;++i) dis[i]=-INF; q.push(s);
            cap[s]=INF; dis[s]=0; while (!q.empty())
            {
                int now=q.front(); vis[now]=0; q.pop();
                for (i=head[now];i;i=e[i].nxt)
                if (e[i].v&&dis[now]+e[i].c>dis[to])
                {
                    dis[to]=dis[pre[to]=now]+e[lst[to]=i].c;
                    if (cap[to]=min(cap[now],e[i].v),!vis[to]) q.push(to),vis[to]=1;
                }
            }
            return dis[t]!=-INF;
        }
        #undef to
    public:
        inline void addedge(CI x,CI y,CI v,CI c)
        {
            e[++cnt]=(edge){y,head[x],v,c}; head[x]=cnt;
            e[++cnt]=(edge){x,head[y],0,-c}; head[y]=cnt;
        }
        inline int solve(CI s,CI t)
        {
            int ret=0,ans=0; while (SPFA(s,t))
            {
                if (ret+dis[t]*cap[t]>=0)
                {
                    ret+=dis[t]*cap[t]; ans+=cap[t];
                    for (int nw=t;nw!=s;nw=pre[nw])
                    e[lst[nw]].v-=cap[t],e[lst[nw]^1].v+=cap[t];
                } else return ans+ret/(-dis[t]);
            }
            return ans;
        }
}NF;
signed main()
{
    RI i,j; for (scanf("%lld",&n),i=1;i<=n;++i) scanf("%lld",&a[i]),ct[i]=resolve(a[i]);
    for (i=1;i<=n;++i) scanf("%lld",&b[i]); for (i=1;i<=n;++i) scanf("%lld",&c[i]);
    for (t=n+1,i=1;i<=n;++i) if (ct[i]&1) NF.addedge(s,i,b[i],0); else NF.addedge(i,t,b[i],0);
    for (i=1;i<=n;++i) if (ct[i]&1) for (j=1;j<=n;++j) if (!(ct[j]&1))
    if ((ct[i]+1==ct[j]&&a[j]%a[i]==0)||(ct[j]+1==ct[i]&&a[i]%a[j]==0))
    NF.addedge(i,j,INF,c[i]*c[j]); return printf("%lld",NF.solve(s,t)),0;
}

原文地址:https://www.cnblogs.com/cjjsb/p/11566672.html

时间: 2024-10-12 06:48:02

Luogu P4068 [SDOI2016]数字配对的相关文章

Luogu P4068 [SDOI2016]数字配对(费用流)

Luogu P4068 [SDOI2016]数字配对(费用流) 根据质因子个数奇偶性划分肯定会形成一张二分图. 把所有的\(a\)分解质因数,记录其质因子个数. \(a_i \% a_j == 0\)且\(a_i\)的质因子比\(a_j\)质因子个数多1的时候,我们连边. 解决这个题目的关键是求出费用\(>0\)的时候的最大的流量. 我们要跑最大费用最大流,(具体实现是把边权取反) 这样在每一次的增广过程中,我们都可以保证费用最大且满足流最多. 但是写法有异议,待填坑. 原文地址:https:/

p4068 [SDOI2016]数字配对

传送门 分析 我们考虑对所有a[i]质因数分解,然后记cnt[i]为a[i]是由几个质数相乘得到的 然后我们建一个二分图,左面为所有cnt[i]为奇数的点,右面是为偶数的点 我们从源点向左面点连容量b[i]花费0的边,从右面点向汇点连容量b[i]花费0的边 然后两排点之间符合条件的点对连容量inf花费c[i]*c[j]的边 然后跑总花费不小于0的最大费用最大流即可 代码 #include<iostream> #include<cstdio> #include<cstring&

【bzoj4514】: [Sdoi2016]数字配对 图论-费用流

[bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后能匹配的两点i,j 连 i->j' cap=inf cost=c[i]*c[j] 跑最大费用流,直到 cost<0 或 全部增广完 最后flow/2就是答案 1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #i

图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在

【BZOJ4514】[Sdoi2016]数字配对 费用流

[BZOJ4514][Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最多进行多少次配对. Input 第一行一个整数 n. 第二行 n 个整数 a1.a2.…….an. 第三行 n 个整数 b1.b2.

4514: [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1305  Solved: 498[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

BZOJ 4514: [Sdoi2016]数字配对

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1606  Solved: 608[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

[Bzoj4514][Sdoi2016]数字配对(费用流)

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2204  Solved: 865[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对.

[Sdoi2016]数字配对

Time Limit: 10 SecMemory Limit: 128 MBSubmit: 1411  Solved: 535[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在获得的价值总和不小于 0 的前提下,求最多进