ZJOI2017

时间:2020-04-20
本文章向大家介绍ZJOI2017,主要包括ZJOI2017使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

仙人掌

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

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

用分治fft可以把时间复杂度优化到$O(nlog_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<<'\n';
    }
}
View Code

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

原文地址:https://www.cnblogs.com/cszmc2004/p/12738416.html