zoukankan      html  css  js  c++  java
  • bzoj3871: [Neerc2013 C]Cactus Automorphisms || 3899: 仙人掌树的同构

    Description

    给定一个N,N<=50 000个节点的仙人掌,其是指每条边最多在一个环中的无向图,求仙人掌有多少种自同构。自同构是指得是图的顶点集合V到V的变换M,

    以P1^a1*P2^a2...Pk^ak的形式输出,其中Pk是素数。

    建圆方树,找到重心,如果重心有两个就在它们之间的边上插一个点,同构变换后重心不变

    以重心为根得到有根树,对于树点,统计交换子树造成的同构,将所有贡献累乘得到答案,对于环点,如果不是重心,就只有翻转这个环能产生新的同构,否则这个环除了翻转还可以旋转,用hash处理这些情况。注意处理环的时候需要把环点的相邻点排成原来在仙人掌上的顺序。

    #include<cstdio>
    #include<algorithm>
    typedef unsigned long long u64;
    const int N=500007;
    int n,m,fac[N];
    int es[N],enx[N],e0[N],e1[N],ep=2;
    bool _c[N];
    void ae(int*e,int a,int b){
        es[ep]=b;enx[ep]=e[a];e[a]=ep++;
        es[ep]=a;enx[ep]=e[b];e[b]=ep++;
    }
    void de(int*e,int a,int b){
        for(int*i=e+a;*i;i=enx+*i){
            int u=es[*i];
            if(u==b){
                *i=enx[*i];
                return;
            }
        }
    }
    int dfn[N],low[N],tk=0,ss[N],sp=0,n1;
    void tj(int w,int pa){
        dfn[w]=low[w]=++tk;
        ss[++sp]=w;
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(!u)continue;
            if(!dfn[u]){
                es[i^1]=0;
                tj(u,w);
                es[i^1]=w;
                if(ss[sp]==u)--sp,ae(e1,w,u);
            }else if(dfn[u]<dfn[w]){
                int rp=0;
                ae(e1,u,++n1);
                _c[n1]=1;
                while(sp&&dfn[ss[sp]]>dfn[u])ae(e1,ss[sp--],n1);
            }
        }
    }
    int sz[N],cg[3],cgp=0,rt;
    void f1(int w,int pa){
        bool is=1;
        sz[w]=1;
        for(int i=e1[w];i;i=enx[i]){
            int u=es[i];
            if(u==pa)continue;
            f1(u,w);
            sz[w]+=sz[u];
            if(sz[u]*2>n1)is=0;
        }
        if(sz[w]*2<n1)is=0;
        if(is)cg[cgp++]=w;
    }
    u64 h[N],h1[N],h2[N];
    int cs[N],cp;
    bool cmp_h(int a,int b){return h[a]<h[b];}
    int a1[N],a2[N],mx=2;
    u64 a3[N];
    void mul(int x){
        ++a1[x];
        if(x>mx)mx=x;
    }
    void mulfac(int x){
        ++a2[x];
        if(x>mx)mx=x;
    }
    void f2(int w,int pa){
        for(int i=e1[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)f2(u,w);
        }
        cp=0;
        for(int i=e1[w],d=0;i;i=enx[i]){
            int u=es[i];
            if(u==pa){
                d=1;
                continue;
            }
            if(d)cs[cp++]=u;
        }
        for(int i=e1[w];i;i=enx[i]){
            int u=es[i];
            if(u==pa)break;
            cs[cp++]=u;
        }
        if(_c[w]){
            if(w==rt){
                u64 p0=29399999,pp=1;
                for(int i=1;i<=cp;++i){
                    h1[i]=h1[i+cp]=h2[i]=h2[i+cp]=h[cs[i-1]];
                    pp*=p0;
                }
                for(int i=1;i<=cp*2;++i)h1[i]+=h1[i-1]*p0;
                for(int i=cp*2;i;--i)h2[i]+=h2[i+1]*p0;
                int c=0;
                for(int i=cp;i<cp*2;++i)c+=(h1[i]-h1[i-cp]*pp==h1[cp]);
                for(int i=cp;i;--i)c+=(h2[i]-h2[i+cp]*pp==h1[cp]);
                mul(c);
            }else{
                u64 h1=0,h2=0;
                for(int i=0;i<cp;++i)h1=h1*1399913+h[cs[i]];
                for(int i=cp-1;i>=0;--i)h2=h2*1399913+h[cs[i]];
                if(h1==h2)mul(2);
                h[w]=std::min(h1,h2);
                h[w]^=h[w]>>13^h[w]*17<<31^41546541735416351llu;
            }
        }else{
            std::sort(cs,cs+cp,cmp_h);
            h[w]=0;
            for(int i=0,j=0;i<cp;i=j){
                for(;j<cp&&h[cs[i]]==h[cs[j]];++j);
                mulfac(j-i);
            }
            for(int i=0;i<cp;++i)h[w]=h[w]*1844677+h[cs[i]];
            h[w]^=h[w]>>17^h[w]*11<<23^12218653252112541llu;
        }
    }
    int _(){
        int x=0,c=getchar();
        while(c<48)c=getchar();
        while(c>47)x=x*10+c-48,c=getchar();
        return x;
    }
    int ps[N],pp,mp[N],ed[N];
    bool np[N];
    int main(){
        n=_();m=_();
        n1=n;
        for(int i=0;i<m;++i){
            pp=_();
            for(int j=0;j<pp;++j)ps[j]=_();
            for(int j=0;j<pp-1;++j)ae(e0,ps[j],ps[j+1]);
        }
        for(int w=1;w<=n;++w){
            for(int i=e0[w];i;i=enx[i]){
                int u=es[i];
                if(ed[u]!=w)ed[u]=w;
                else if(u>w)--a1[2];
            }
        }
        tj(1,0);
        f1(1,0);
        if(cgp==2){
            if(_c[cg[0]])rt=cg[0];
            else if(_c[cg[1]])rt=cg[1];
            else{
                rt=++n1;
                ae(e1,n1,cg[0]);
                ae(e1,n1,cg[1]);
                de(e1,cg[0],cg[1]);
                de(e1,cg[1],cg[0]);
            }
        }else rt=cg[0];
        f1(rt,0);
        f2(rt,0);
        for(int i=mx;i;--i)a2[i]+=a2[i+1];
        for(int i=mx;i;--i)a2[i]+=a1[i];
        pp=0;
        for(int i=2;i<=mx;++i){
            if(!np[i])ps[pp++]=mp[i]=i;
            for(int j=0;j<pp&&i*ps[j]<=mx;++j){
                np[i*ps[j]]=1;
                mp[i*ps[j]]=ps[j];
                if(i%ps[j]==0)break;
            }
        }
        for(int i=2;i<=mx;++i){
            for(int x=i;x>1;x/=mp[x])a3[mp[x]]+=a2[i];
        }
        pp=0;
        for(int i=2;i<=mx;++i)if(a3[i])ps[pp++]=i;
        printf("%d
    ",pp);
        for(int j=0;j<pp;++j)printf("%d %lld
    ",ps[j],a3[ps[j]]);
        return 0;
    }
    View Code
  • 相关阅读:
    编辑器 --- Visual Studio Code 英文界面转换成中文(简体)
    CSS3 -- column 实现瀑布流布局
    CSS3 -- 边框圆角
    CSS3 -- 弹性盒
    自适应布局要素
    Vue -- 基础知识
    Vue -- element-ui el-table 的合计在第一行显示并可点击
    如何在网页标题栏title加入logo(icon)图标?
    linux下暴力破解工具hydra【转】
    linux 服务简介
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7016904.html
Copyright © 2011-2022 走看看