牛客练习赛21 D

6 篇文章 0 订阅
5 篇文章 0 订阅

将满足题意的(i,j),(p,q)预处理出来,然后向质因子连边跑网络流即可。
这里写图片描述坑了一下午,这样写常数巨大。改成define就过了……
题面:https://www.nowcoder.com/acm/contest/130/D
代码:

//include <bits/stdc++.h>
#pragma GCC optimize(2)
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <cmath>
#include <cstring>
#define db double
#define LL long long
//#define int LL
#define rep(i,x,y) for (int i=x;i<=y;++i)

using namespace std;
const int N  =  504;
//const int mod = /;
const int INF =1<<30;
void read(int &x)
{
    int f=1;
    x=0;
    char ch=getchar();
    while (!isdigit(ch)) (ch=='-'?f=-1:0),ch=getchar();
    while ( isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    x*=f;
    return ;
}
struct xx
{
    int V,next,cap;
}bb[N*N*20];
int c[N*N*10];
int G,head[N*N*10],cur[N*N*10];
void add(int x,int y,int z)
{
    bb[++G]=(xx){y,head[x],z};
    head[x]=G;
    bb[++G]=(xx){x,head[y],0};
    head[y]=G;
}
int S,T;//queue <int > q;
int q[N*N*10];
int level[N*N*10];

inline int BFS()
{
    int hd=1,tl=1;
    //q.push(S);
    q[1]=S;
    memset(level,0,sizeof(level));
    level[S]=1;
    while (hd<=tl)
    {
        int u=q[hd];++hd;
        for (int i=head[u];i;i=bb[i].next)
        {
            int v=bb[i].V;
            if (bb[i].cap&&!level[v]) level[v]=level[u]+1,q[++tl]=v;
        }
    }
    return level[T];
}

int dfs(int x,int a)
{
    if (x==T||a==0) return a;
    int flow=0,f;
    for (int &i=cur[x];i;i=bb[i].next)
    {
        #define v bb[i].V
        if (level[v]==level[x]+1&&bb[i].cap&&(f=dfs(v,min(bb[i].cap,a)))<=a)
        {
            a-=f;
            flow+=f;
            bb[i].cap-=f;
            bb[i^1].cap+=f;
            if (a==0) break;
        }
    }
    return flow;
}
int cnt;
int Dinic()
{
    int flow=0;
    while (BFS())
    {
        rep(i,1,cnt) cur[i]=head[i];
        flow+=dfs(S,INF);
    }
    return flow;
}
int tp[2],t,n,a[N],b[N];
int gcd(int x,int y)
{
    return y?gcd(y,x%y):x;
}
int s[2][N*N],Q;
int pri[32000],mn[32000];
void mk_tb(int n,int *p)
{
    rep(i,2,n)
    {
        if (!mn[i]) p[mn[i]=++*p]=i;
        for (int j=1;j<=mn[i]&&(LL)i*p[j]<=n;++j) mn[i*p[j]]=j;
    }
}
map <int,int >id;
signed main()
{
    //  freopen("data.txt","r",stdin);
//  freopen("Moon.txt","w",stdout);
    read(Q);
    mk_tb(32000,pri);
    while (Q--)
    {
        id.clear();
        cnt=tp[1]=tp[0]=t=0;
        G=1;
        memset(head,0,sizeof(head));
        read(n);
        rep(i,1,n) read(a[i]);
        rep(i,1,n) read(b[i]);
        rep(i,1,n)
          rep(j,1,n)
            {
                int tmp=gcd(a[i],b[j]);
                if (a[i]<b[j]&&tmp>1) ++cnt,s[0][++tp[0]]=cnt,c[cnt]=tmp;
                if (a[i]>b[j]&&tmp>1) ++cnt,s[1][++tp[1]]=cnt,c[cnt]=tmp;
            }
        S=++cnt,T=++cnt;
        rep(i,1,tp[0])
        {add(S,s[0][i],1);
            int tmp=sqrt(c[s[0][i]]);
            int k=c[s[0][i]];
             for (int j=1;pri[j]<=k&&pri[j]<=tmp&&j<=pri[0];++j)
                if (k%pri[j]==0)
            {
                if (!id.count(pri[j])) id[pri[j]]=++cnt;
                add(s[0][i],id[pri[j]],1);
                while (k%pri[j]==0) k/=pri[j];
             }
            if (k>1)
            {
                if (!id.count(k)) id[k]=++cnt;
                add(s[0][i],id[k],1);
            }
        }

        rep(i,1,tp[1])
        { add(s[1][i],T,1);
            int tmp=sqrt(c[s[1][i]]);
            int k=c[s[1][i]];
             for (int j=1;pri[j]<=tmp&&pri[j]<=k&&j<=pri[0];++j)
                if (k%pri[j]==0)
            {
                if (id.count(pri[j])) //continue;//id[pri[j]]=++cnt;
                add(id[pri[j]],s[1][i],1);
                while (k%pri[j]==0) k/=pri[j];
             }
            if (k>1)
            {
                if (id.count(k))// id[k]=++cnt;
                add(id[k],s[1][i],1);
            }
        }
        printf("%d\n",Dinic());
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值