zoukankan      html  css  js  c++  java
  • 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]

  • 相关阅读:
    使用Apache搭建个人用户主页
    Linux搭建ftp服务器,并建立本地用户与虚拟用户
    Linux搭建FTP服务器,并建立匿名用户登录
    用虚拟机安装RHEL7
    基于OpenStack构建企业私有云(5)Neutron
    基于OpenStack构建企业私有云(3)Glance
    基于OpenStack构建企业私有云(1)实验环境准备
    基于OpenStack构建企业私有云(2)KeyStone
    python--003--百分号字符串拼接、format
    python--002--数据类型(set)
  • 原文地址:https://www.cnblogs.com/cszmc2004/p/12738416.html
Copyright © 2011-2022 走看看