P4068 [SDOI2016]数字配对

【题意】

P4068 [SDOI2016]数字配对

 

 【分析】

我们发现直接n^2次判断就已经超时

所以我们需要考虑优化

如果a是b的倍数,且a的质因数分解的次方和比b多1,那么就可以建边

显然这里就可以建立二分图了

 

建好图以后,题目要求费用大于0的情况下的最大流

那么我们就贪心的增广,如果当前增广路的费用大于0,那就随便增

如果小于0,就增到费用不够为止

 

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mp make_pair
#define fi firstP
#define se second
const int maxn=200+5;
const int maxm=8e3+5;
int n,m,head[maxn];
struct edge
{
    int to,nxt;
    ll v,c;
}e[maxm<<1];
int tot=1,S,T;
void add(int x,int y,ll z,ll c)
{
    e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; e[tot].c=c; head[x]=tot;
    e[++tot].to=x; e[tot].nxt=head[y]; e[tot].v=0; e[tot].c=-c; head[y]=tot;  
}
const ll inf=1e18;
ll dis[maxn];
int vis[maxn],pre[maxn];
bool spfa()
{
    for(int i=S;i<=T;i++)
        vis[i]=0,dis[i]=-inf;
    dis[S]=0;
    queue <int> q;
    q.push(S); vis[S]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(dis[to]<dis[u]+e[i].c && e[i].v>0)
            {
                dis[to]=dis[u]+e[i].c;
                pre[to]=i;
                if(!vis[to])
                {
                    q.push(to);
                    vis[to]=1;
                }
            }
        }
        vis[u]=0;
    }
    return (dis[T]!=-inf);
}
ll mcmf()
{
    ll cost=0,sumflow=0;
    while(spfa())
    {
       ll flow=inf,co=0;
        for(int i=T;i!=S;i=e[pre[i]^1].to)
            flow=min(flow,e[pre[i]].v),co+=e[pre[i]].c;
        if(cost+co<0) return sumflow;
        if(co<0)
            flow=min(flow,cost/(-co));
        for(int i=T;i!=S;i=e[pre[i]^1].to)
        {
            e[pre[i]].v-=flow; e[pre[i]^1].v+=flow;
            cost+=e[pre[i]].c*flow;
        }
        sumflow+=flow;
    }
    return sumflow;
}
int a[maxn],cnt[maxn],b[maxn],c[maxn];
int calc(int x)
{
    int tot=0,lim=sqrt(x);
    for(int i=2;i<=lim;i++)
        while(x%i==0)
            x/=i,tot++;
    if(x>1) tot++;
    return tot;
}
int main()
{
    // freopen("a.in","r",stdin);
    // freopen("a.out","w",stdout);
    scanf("%d",&n);
    S=0; T=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++) cnt[i]=calc(a[i]);
    for(int i=1;i<=n;i++)
        if(cnt[i]&1)
            for(int j=1;j<=n;j++)
                if((a[i]%a[j]==0 && cnt[i]==cnt[j]+1) || (a[j]%a[i]==0 && cnt[j]==cnt[i]+1))
                    add(i,j,inf,1LL*c[i]*c[j]);
    for(int i=1;i<=n;i++)
        if(cnt[i]&1) add(S,i,b[i],0);
        else add(i,T,b[i],0);
    printf("%lld",mcmf());
    return 0;
}

 

上一篇:P4069 [SDOI2016]游戏 树剖+李超树


下一篇:对于System.Net.Http的学习(二)——使用 HttpClient 进行连接