清北NOIP训练营内部试题解析

网友投稿 2018-02-09 11:17

https://cdn.china-scratch.com/timg/180211/111J54460-0.jpg

解析在代码后面

代码

#include

#define N 100001

using namespace std;

typedef long long LL;

int to[N],d[N],q[N],sum;

const int mod=1e9+7;

LL pow(LL a,int b)

{

    LL res=1;

    for(;b;b>>=1,a=a*a%mod)

        if(b&1) res=res*a%mod;

    return res;

}

void dfs(int x)

{

    sum++;

    d[x]=0;

    if(d[to[x]]) dfs(to[x]);

}

int main()

{

    freopen("road.in","r",stdin);

    freopen("road.out","w",stdout);

    int n;

    scanf("%d",&n);

    for(int i=1;i<=n;i++) scanf("%d",&to[i]),d[to[i]]++;

    int h=1,t=0;

    for(int i=1;i<=n;i++)

        if(!d[i]) q[++t]=i;

    while(h<=t)

    {

        if(!(--d[to[q[h]]])) q[++t]=to[q[h]];

        ++h;

    }

    LL ans=pow(2,t); 

    for(int i=1;i<=n;i++)

        if(d[i])

        {

            sum=0;

            dfs(i);

            ans=ans*(pow(2,sum)-2)%mod;

        }

    printf("%I64d",ans);

}

设图中有m个环,每个环有si条边,有k条边不在环中

ans= (2^s1 -2)*( 2^s2 -2)* (2^s3 -2)…… *( 2^sm -2)* 2^k

(环上的边只有两种可能形成环)


找环好找,怎么找树?

一种方法是tarjan找出所有的环,总边数-环的边数=树的边数

std用了拓扑排序


--end--

声明:本文章由网友投稿作为教育分享用途,如有侵权原作者可通过邮件及时和我们联系删除:freemanzk@qq.com