• AGC008E Next or Nextnext


    Link
    如果我们(i ightarrow p_i)建边,那么最后会得到一些有向环。
    对于上述的每一个环,如果我们(i ightarrow a_i)建边,那么此时(a_i)(i)在顺时针方向下的第(1operatorname{or}2)个点,也就是(a_i=p_ivee a_i=p_{p_i})
    那么此时有四种情况:
    (a_i=p_i),那么这个环不变。
    (a_i=p_{p_i}),那我们对环长的奇偶性分开讨论。
    若环长为奇数,那么这个环变成元素相同的另一个环。
    若环长为偶数,那么这个环会被拆成两个环。
    否则部分(a_i=p_i),部分(a_i=p_{p_i}),那么这个环会被拆成一个环和若干个指向环的链构成的基环内向树。
    现在我们只有(i ightarrow a_i)建出来的图,所以我们倒过来考虑。
    如果这不是由若干个环和基环内向树构成的森林,那么答案为(0)
    求出对于任意一个(l),有多少个环长度为(l),然后利用do求出对于一个环长而言的方案数,最后再根据乘法原理乘起来就好了。
    假如现在长度为(l),设(f_i)表示有(i)个长度为(l)的环的方案数,那么有:

    [f_j= egin{cases} 1&j=0\ 1+[i e1wedge2 mid i]&j=1\ i(j-1)f_{j-2}+f_if_{j-1}& ext{otherwise} end{cases} ]

    然后就只需要考虑基环内向树的方案数了。
    我们把每条链(包括环上的点)单独拿出来,那么这个环会被剖成很多份。
    假设一条链长为(l),从这条链顺时针的一段环的长度为(d),那么:
    (dle l),则答案为(0);若(d=l),则方案数为(1);若(d>l),则方案数为(2)
    然后根据乘法原理把基环内向树的答案和环的答案乘在一起就好了。

    #include<cstdio>
    #include<cctype>
    const int N=100007,P=1000000007;
    int a[N],deg[N],vis[N],pre[N],cnt[N],f[N];
    int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
    int add(int a,int b){return a+=b-P,a+(a>>31&P);}
    int mul(int a,int b){return 1ll*a*b%P;}
    int main()
    {
        int n=read(),ans=1;
        for(int i=1;i<=n;++i) ++deg[a[i]=read()];
        for(int i=1,p;(p=i)<=n;++i)
        {
    	if(deg[i]>2) return puts("0"),0;
    	if(deg[i]<2||vis[i]) continue;
    	do
    	{
    	    if(vis[p]) return puts("0"),0;
    	    vis[p]=1,pre[a[p]]=p,p=a[p];
    	}while(p^i);
        }
        for(int i=1,p,l1,l2;i<=n;++i)
    	if(!deg[i])
    	{
    	    for(p=i,l1=0,l2=0;!vis[p];p=a[p]) vis[p]=1,++l1;
    	    do ++l2,p=pre[p]; while(deg[p]^2);
    	    if(l1<l2) ans=add(ans,ans); else if(l1>l2) return puts("0"),0;
    	}
        for(int i=1;i<=n;++i)
    	if(!vis[i])
    	{
    	    int p=i,l=0;
    	    do ++l,p=a[p],vis[p]=1; while(p^i);
    	    ++cnt[l];
    	}
        for(int i=1;i<=n;ans=mul(ans,f[cnt[i++]]))
        {
    	f[0]=1,f[1]=1+(i^1&&i&1);
    	for(int j=2;j<=cnt[i];++j) f[j]=add(mul(i,mul(j-1,f[j-2])),mul(f[1],f[j-1]));
        }
        printf("%d",ans);
    }
    
  • 相关阅读:
    Kera高层API002
    Kera高层API
    手写数字问题实战(层)
    函数优化实战
    反向传播算法
    链式法则
    多输出感知机及其梯度
    JDBC
    mysql查询操作1
    内部类
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12639824.html
Copyright © 2020-2023  润新知