2018.10.29 洛谷P4129 [SHOI2006]仙人掌(仙人掌+高精度)

传送门
显然求出每一个环的大小。
A n s = ∏ i ( s i z [ i ] + 1 ) Ans=\prod_i(siz[i]+1) Ans=i(siz[i]+1)
注意用高精度存答案。
代码:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
const int N=2e4+5,M=1e6+5;
int n,m,first[N],cnt=0,dfn[N],low[N],du[N],dep[N],fa[N],tot=0,siz=0;
struct edge{int v,next;}e[M<<1];
struct bignum{
    int s[N<<1],len;
    bignum(){memset(s,0,sizeof(s)),len=0;}
    inline bignum operator=(int x){
        while(x)s[++len]=x-x/10*10,x/=10;
        return *this;
    }
    inline bignum operator*(const bignum&x){
        bignum ret;
        int maxlen=x.len+len-1;
        for(int i=1;i<=len;++i)for(int j=1;j<=x.len;++j)ret.s[i+j-1]+=s[i]*x.s[j];
        for(int i=1;i<=maxlen;++i)if(ret.s[i]>=10)ret.s[i+1]+=ret.s[i]/10,ret.s[i]=ret.s[i]-ret.s[i]/10*10;
        while(ret.s[maxlen+1]){
            ++maxlen;
            if(ret.s[maxlen]>=10)ret.s[maxlen+1]+=ret.s[maxlen]/10,ret.s[maxlen]=ret.s[maxlen]-ret.s[maxlen]/10*10;
        }
        return ret.len=maxlen,ret;
    }
    inline void output(){for(int i=len;i;--i)printf("%d",s[i]);}
}ans;
inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
inline void calc(int st,int ed){
    for(int i=ed;i!=st;i=fa[i])if(++du[i]==2)puts("0"),exit(0);
    bignum tmp;
    tmp=(dep[ed]-dep[st]+2);
    ans=ans*tmp;
}
inline void tarjan(int p){
    ++siz;
    dfn[p]=low[p]=++tot;
    for(int i=first[p];i;i=e[i].next){
        int v=e[i].v;
        if(v==fa[p])continue;
        if(!dfn[v])dep[v]=dep[p]+1,fa[v]=p,tarjan(v),low[p]=min(low[p],low[v]);
        else low[p]=min(low[p],dfn[v]);
    }
    for(int i=first[p];i;i=e[i].next){
        int v=e[i].v;
        if(fa[v]!=p&&dfn[p]<dfn[v])calc(p,v);
    }
}
int main(){
    n=read(),m=read(),ans.len=ans.s[1]=1;
    while(m--){
        int k=read()-1,x=read(),y;
        while(k--)y=read(),add(y,x),add(x,y),x=y;
    }
    tarjan(1);
    if(siz!=n)puts("0"),exit(0);
    ans.output();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值