zoukankan      html  css  js  c++  java
  • 【CF498C】Array and Operations-最大流+数论

    测试地址:Array and Operations
    题目大意:给定一个包含n个元素的数列Am个数对(ik,jk),保证ik+jk是奇数,每次操作从m个数对里选一个,然后将AikAjk同除一个不等于1的公因数v,问最多能执行多少次操作。
    做法:本题需要用到最大流+数论。
    首先显然的是,如果一次操作中我们选择的v不是质数,那显然把它拆成若干次v是质数的操作更优,那么问题就变成了:每次选取满足要求的一对数,同除一个质数,问能操作多少次。我们发现题目中还有一个重要的条件:ik+jk为奇数,那么ikjk一定有一个是奇数,另一个是偶数,因此我们可以把数列中的元素按下标的奇偶分成两个集合。我们发现这就有点二分图匹配的影子了,但又不完全是,所以还要进一步转化。
    注意到v为不同质数时的操作是不会相互影响的,因此我们将数列中的元素质因数分解,时间复杂度为O(nAi),我们发现,进行一次操作实际上就等价于,找到了一条关于质因子的匹配边,那么问题就变成了二分图最大匹配,这里为了方便,我是用最大流写的。而一个数的质因子数目最多有logAi个,所以一共有nlogAi个点,复杂度可以接受。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int n,m,a[110],S,T;
    int f[110][11],id[110][11],num[110][11],totid=0;
    int first[1010]={0},tot=1;
    int h,t,q[1010],lvl[1010],cur[1010];
    struct edge
    {
        int v,next,f;
    }e[20010];
    
    void findfactor(int x)
    {
        f[x][0]=0;
        int now=a[x];
        for(int i=2;i<=40000;i++)
            if (now%i==0)
            {
                f[x][++f[x][0]]=i;
                id[x][f[x][0]]=++totid;
                num[x][f[x][0]]=0;
                while(now%i==0) now/=i,num[x][f[x][0]]++;
            }
        if (now)
        {
            f[x][++f[x][0]]=now;
            id[x][f[x][0]]=++totid;
            num[x][f[x][0]]=1;
        }
    }
    
    void insert(int a,int b,int f)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,first[b]=tot;
    }
    
    void init()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            findfactor(i);
        }
    
        S=totid+1,T=totid+2;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=f[i][0];j++)
            {
                if (i%2) insert(S,id[i][j],num[i][j]);
                else insert(id[i][j],T,num[i][j]);
            }
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if (b%2) swap(a,b);
            int tmp1=1,tmp2=1;
            while(tmp1<=f[a][0]&&tmp2<=f[b][0])
            {
                if (f[a][tmp1]==f[b][tmp2])
                {
                    insert(id[a][tmp1],id[b][tmp2],inf);
                    tmp1++;
                }
                else if (f[a][tmp1]<f[b][tmp2]) tmp1++;
                else tmp2++;
            }
        }
    }
    
    bool makelevel()
    {
        for(int i=1;i<=T;i++)
            lvl[i]=-1,cur[i]=first[i];
        h=t=1;
        q[1]=S;
        lvl[S]=0;
        while(h<=t)
        {
            int v=q[h++];
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&lvl[e[i].v]==-1)
                {
                    lvl[e[i].v]=lvl[v]+1;
                    q[++t]=e[i].v;
                }
        }
        return lvl[T]!=-1;
    }
    
    int maxflow(int v,int maxf)
    {
        int ret=0,f;
        if (v==T) return maxf;
        for(int i=cur[v];i;i=e[i].next)
        {
            if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
            {
                f=maxflow(e[i].v,min(maxf-ret,e[i].f));
                ret+=f;
                e[i].f-=f;
                e[i^1].f+=f;
                if (ret==maxf) break;
            }
            cur[v]=i;
        }
        if (!ret) lvl[v]=-1;
        return ret;
    }
    
    void dinic()
    {
        int maxf=0;
        while(makelevel())
            maxf+=maxflow(S,inf);
        printf("%d",maxf);
    }
    
    int main()
    {
        init();
        dinic();
    
        return 0;
    }
  • 相关阅读:
    HDU 5583 Kingdom of Black and White 水题
    HDU 5578 Friendship of Frog 水题
    Codeforces Round #190 (Div. 2) E. Ciel the Commander 点分治
    hdu 5594 ZYB's Prime 最大流
    hdu 5593 ZYB's Tree 树形dp
    hdu 5592 ZYB's Game 树状数组
    hdu 5591 ZYB's Game 博弈论
    HDU 5590 ZYB's Biology 水题
    cdoj 1256 昊昊爱运动 预处理/前缀和
    cdoj 1255 斓少摘苹果 贪心
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793432.html
Copyright © 2011-2022 走看看