• ZJOI2017


    仙人掌

    实际上我们只需要解决树的部分分即可。因为如果我们在加上边时,肯定无法加在原来的环上。

    所以可以把所有环删除后再进行dp。实际上可以对每个连通块分别dp,答案是所有连通块dp结果的乘积。

    用分治fft可以把时间复杂度优化到$O(nlog^2_2n)$,jzoj上有一道题是这道题的变体,那道题不需要转化模型,但是需要使用分治fft。

    但是这道题用分治fft肯定是会超时的。

    转化模型后,这道题的模型是“使用任意多条链(可以只包含一条边)覆盖整个图的方案数”。原题要求没有重边,但是可以“不用覆盖每条边”,所以可以把未被覆盖的边都加上一个自环,转变成前面所述的问题。

    设g[i]表示有i个点,互相连边的方案,可以得到

    g[n]=g[n-1]+g[n-2]*(n-1)。处理g时间复杂度O(n)

    如果当前节点是根的话,则不能向外连边,那么再乘上g[儿子个数]即可(就是把儿子的方案组合在一起)u

    否则当前点可以向外连边。把现在的节点算进来,就是要乘以g[儿子个数+1]

    时间复杂度O(n)

    #include<bits/stdc++.h>
    using namespace std;
    #define mo 998244353ll
    #define int long long
    #define N 1000010
    int t,n,m,ec,h[N],v[N],fa[N],dfn[N],ct,nxt[N],x,y,f[N],ok,vi[N],d[N];
    void add(int x,int y){v[++ec]=y;nxt[ec]=h[x];h[x]=ec;}
    void dfs(int x){
        dfn[x]=++ct;
        for(int i=h[x];i;i=nxt[i]){
            if(!dfn[v[i]]){
                fa[v[i]]=x;
                dfs(v[i]);
            } 
            else if(v[i]!=fa[x]&&dfn[v[i]]>dfn[x]){
                d[x]-=2;
                for(int y=v[i];y!=x;y=fa[y]){
                    if(vi[y]){
                        ok=1;
                        return;
                    }
                    vi[y]=1;
                    d[y]-=2;
                }
            }
            if(ok)return;
        }
    }
    signed main(){
        freopen("cactus.in","r",stdin);
        freopen("cactus.out","w",stdout);
        cin>>t;
        while(t--){
            scanf("%lld%lld",&n,&m);
            ec=ok=0;
            for(int i=1;i<=n;i++)
                h[i]=dfn[i]=vi[i]=d[i]=0;
            while(m--){
                int x,y;
                scanf("%lld%lld",&x,&y);
                add(x,y);
                add(y,x);
                d[x]++;
                d[y]++;
            }
            f[0]=f[1]=1;
            for(int i=2;i<=n;i++)
                f[i]=(f[i-1]+f[i-2]*(i-1)%mo)%mo;
            for(int i=1;i<=n;i++)
                if(!dfn[i])dfs(i);
            int ans=1;
            for(int i=1;i<=n;i++)
                ans=ans*f[d[i]]%mo;
            if(ok)ans=0; 
            cout<<ans<<'
    ';
        }
    }
    View Code

    树状数组

    如果打表,发现原代码维护的是后缀信息。

    g[n]=g[ng[n]=g[n1]+g[n2]

  • 相关阅读:
    20172021年福建省普通高校分数线,招生报考及录取统计(理科)
    SUSE Linux Enterprise 15 SP1 系统安装
    常见的网络服务器软件综合比较介绍(apache、IIS、tomcat、jboss、resin、weblogic、websphere)
    车载继电器工作原理
    java线程池使用实例
    dubbo入门教程:基于dubbo实现服务之前调用
    Sentinal
    微服务之服务网关
    ElasticSearch查询(二)
    微服务之配置管理中心
  • 原文地址:https://www.cnblogs.com/cszmc2004/p/12738416.html
Copyright © 2020-2023  润新知