列表

详情


NC20525. [ZJOI2017]仙人掌

描述

如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌。所谓简单环即不经过 重复的结点的环。 
 
现在九条可怜手上有一张无自环无重边的无向连通图,但是她觉得这张图中的边数太少了,所以她想要在图上连上 一些新的边。同时为了方便的存储这张无向图,图中的边数又不能太多。经过权衡,她想要加边后得到的图为一棵仙人掌。不难发现合法的加边方案有很多,可怜想要知道总共有多少不同的加边方案。两个加边方案是不同的当且 仅当一个方案中存在一条另一个方案中没有的边。

输入描述

多组数据,第一行输入一个整数T表示数据组数。
每组数据第一行输入两个整数n,m,表示图中的点数与边数。
接下来m行,每行两个整数u,v(1 ≤ u,v ≤ n,u!=v)表示图中的一条边。
保证输入的图联通且没有自环与重边
Sigma(n) ≤ 5*10^5,m ≤ 10^6,1 ≤ m ≤ n*(n-1)/2

输出描述

对于每组数据,输出一个整数表示方案数,当然方案数可能很大,请对998244353取模后输出。

示例1

输入:

2
3 2
1 2
1 3
5 4
1 2
2 3
2 4
1 5

输出:

2
8

说明:

对于第一组样例合法加边的方案有 {}, {(2,3)},共 2 种。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 773ms, 内存消耗: 86744K, 提交时间: 2019-03-14 18:06:23

#include<cstdio>  
#include<iostream>  
#include<algorithm>  
#include<cstdlib>  
#include<cstring>
#include<string>
#include<climits>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#define LL long long
 
using namespace std;
 
inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}
 
inline void read(int &x){
  char c=nc();int b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
 
inline void read(LL &x){
  char c=nc();LL b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline int read(char *s)
{
    char c=nc();int len=0;
    for(;!(c>='A' && c<='Z');c=nc()) if (c==EOF) return 0;
    for(;(c>='A' && c<='Z');s[len++]=c,c=nc());
    s[len++]='\0';
    return len;
}

inline void read(char &x){
  for (x=nc();!(x>='A' && x<='Z');x=nc());
}

int wt,ss[19];
inline void print(int x){

    if (x<0) x=-x,putchar('-');
    if (!x) putchar(48); else {
    for (wt=0;x;ss[++wt]=x%10,x/=10);
    for (;wt;putchar(ss[wt]+48),wt--);}
}
inline void print(LL x){
    if (x<0) x=-x,putchar('-');
    if (!x) putchar(48); else {for (wt=0;x;ss[++wt]=x%10,x/=10);for (;wt;putchar(ss[wt]+48),wt--);}
}

int T,n,m,s,flag,v[500010];
vector<int> b[500010];
LL g[500010],f[500010];
const LL mo=998244353;
struct tree
{
    int a,b,dfs,low;
}a[500010];
map<int,bool> c[500010];

int dep[500010],dfn[500010],fa[500010],lu[500010],cnt;

void init()
{
    for (int i=1;i<=n;i++)
        b[i].clear(),a[i].dfs=a[i].low=a[i].a=a[i].b=0,c[i].clear(),dfn[i]=0,dep[i]=0,fa[i]=0;
    g[1]=1LL,g[0]=1LL;
    for (int i=2;i<=n;i++)
        g[i]=(g[i-1]+g[i-2]*(LL)(i-1)%mo)%mo;
}

void dfs(int x,int p)
{
    fa[x]=p,dfn[x]=++cnt,dep[x]=dep[p]+1;
    for (int i=0;i<b[x].size();i++)
        if (!dfn[b[x][i]]) dfs(b[x][i],x);
}

bool check()
{
    cnt=0;
    dfs(1,0);
    int u,v;
    memset(lu,0,sizeof(lu));
    for (int i=1;i<=n;i++)
        for (int j=0;j<b[i].size();j++)
        if (i<b[i][j])
        {
            u=i,v=b[i][j];
            if (dfn[u]<dfn[v]) swap(u,v);
            while (u!=v)
            {
                if (lu[u]==2) return false;
                lu[u]++,u=fa[u];
            }
        }
    return true;
}

void dp(int x,int y)
{
    v[x]=1;f[x]=1;
    int sum=0;
    for (int i=0;i<b[x].size();i++)
        if (!v[b[x][i]] && !c[x][b[x][i]])
        {
            dp(b[x][i],y);
            f[x]=f[x]*f[b[x][i]]%mo;
            sum++;
        }
    if (x==y) f[x]=f[x]*g[sum]%mo;
    else f[x]=f[x]*g[sum+1]%mo;
}

void work(int x)
{
    for (int i=0;i<b[x].size();i++)
        if (v[b[x][i]] && b[x][i]!=fa[x])
        {
            int y=b[x][i];
            c[x][y]=1,c[y][x]=1;
            while (x!=y)
            {
                c[x][fa[x]]=1;c[fa[x]][x]=1;
                x=fa[x];
            }
            return ;
        }
        else if (!v[b[x][i]]) 
            v[b[x][i]]=1,fa[b[x][i]]=x,work(b[x][i]),v[b[x][i]]=0;
}

int main()
{
    read(T);
    while(T--)
    {
        read(n);read(m);
        int x,y;
        init();
        for (int i=1;i<=m;i++)
            read(x),read(y),b[x].push_back(y),b[y].push_back(x);
        if (!check()) {print(0),puts("");continue;}
        for(int i=1;i<=n;i++) v[i]=0;
        v[1]=1;work(1);
        LL res=1;
        for(int i=1;i<=n;i++) v[i]=0;
        for (int i=1;i<=n;i++)
            if (!v[i]) dp(i,i),res=res*f[i]%mo;
        print(res);puts("");
    }
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 358ms, 内存消耗: 23672K, 提交时间: 2019-03-09 14:12:12

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

typedef long long ll;

inline int read()
{
    int x=0;char ch=getchar();
    while(ch<'0' || '9'<ch)ch=getchar();
    while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
    return x;
}

const int N=5e5+9;
const int M=1e6+9;
const int md=998244353;

int to[M],nxt[M],beg[N],tot;
int n,m,fa[N],dep[N],dfn[N],path[N],a[N],dfs_clock;
ll f[N],g[N],ans;

inline void adde(int u,int v)
{
    to[++tot]=v;
    nxt[tot]=beg[u];
    beg[u]=tot;
}

inline void add(int u,int v)
{
    adde(u,v),adde(v,u);
}

void dfs(int u)
{
    dfn[u]=++dfs_clock;

    for(int i=beg[u],v;i;i=nxt[i])
        if((v=to[i])!=fa[u] && !dfn[v])
        {
            fa[v]=u;
            dep[v]=dep[u]+1;
            dfs(v);
        }
}

inline bool cmp(int a,int b)
{
    return dep[a]<dep[b];
}

void dfs2(int u,bool isrt)
{
    f[u]=1;
    path[u]=-1;
    int soncnt=0;

    for(int i=beg[u],v;i;i=nxt[i])
        if((v=to[i])!=fa[u] && path[v]==1)
        {
            soncnt++;
            dfs2(v,0);
            (f[u]*=f[v])%=md;
        }

    if(soncnt==0)
        return;

    if(isrt)
        (f[u]*=g[soncnt])%=md;
    else
        (f[u]*=g[soncnt+1])%=md;
}

int main()
{
    g[0]=g[1]=1;
    for(int i=2;i<N;i++)
        g[i]=(g[i-1]+g[i-2]*(i-1))%md;

    int T=read();
    while(T--)
    {
        n=read();
        m=read();

        tot=1;
        for(int i=1;i<=n;i++)
            beg[i]=fa[i]=dfn[i]=dep[i]=path[i]=0;

        for(int i=1;i<=m;i++)
            add(read(),read());

        tot=0;
        dep[1]=1;
        fa[1]=0;
        dfs(1);

        for(int i=1;i<=m;i++)
        {
            int st=to[i<<1],ed=to[i<<1|1];
            if(dfn[st]<dfn[ed])
                swap(st,ed);

            while(st!=ed)
            {
                path[st]++;
                if(path[st]>2)
                    goto wa;
                st=fa[st];
            }
        }

        if(0)
        {
            wa:;
            puts("0");
            continue;
        }

        for(int i=1;i<=n;i++)
            a[i]=i;
        sort(a+1,a+n+1,cmp);

        ans=1ll;
        for(int i=1;i<=n;i++)
            if(path[a[i]]!=-1)
            {
                dfs2(a[i],1);
                (ans*=f[a[i]])%=md;
            }

        printf("%lld\n",ans);
    }

    return 0;
}

上一题