ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF711D Directed Roads 题解

2021-11-02 08:00:52  阅读:200  来源: 互联网

标签:Directed cnt 题解 ll low ans Roads mod rightarrow


Description

洛谷传送门

Solution

看到 \(n\) 个点 \(n\) 条边,显然的基环树(可能是基环树森林),所以我们对于环上的点和非环上的点分别处理。

假设一共有 \(cnt\) 个环,每个环上有 \(d_i\) 个点,我们来分类讨论一下:

  • 对于环上的点,我们发现只有两种情况会产生环,即

    • \(1 \rightarrow 2 \rightarrow 3 \rightarrow ··· \rightarrow d_i - 1 \rightarrow d_i\)
    • \(d_i \rightarrow d_i - 1 \rightarrow ··· \rightarrow 3 \rightarrow 2 \rightarrow 1\)

    所以我们用总情况数减去 \(2\)即可。方案数:

    \[ans = \prod\limits_{i = 1}^{cnt}{(2^{d_i} - 2)} \]

  • 对于非环上的点,我们发现不论朝哪个方向连,都不会影响是否会产生环,所以方案数为 \(2^{非环上点的个数}\):

    \[ans = 2^{n - \sum\limits_{i = 1}^{cnt}d_i} \]

至此,我们就讨论完了(事实上还是很简单的),总结一下:

\[ans = \prod\limits_{i = 1}^{cnt}{(2^{d_i} - 2)} \times 2^{n - \sum\limits_{i = 1}^{cnt}d_i} \]

那么如何找环呢?我这里写了个 Tarjan 缩点,大小大于 2 的强连通分量就是环(感觉用牛刀杀鸡了……不管了)。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long

using namespace std;

const ll mod = 1e9 + 7;
const ll N = 2e5 + 10;
ll n;
struct node{
    ll v, nxt;
}edge[N];
ll head[N], tot;
ll dfn[N], low[N], tim;
ll stk[N], top, t[N];
ll cnt, siz[N];

inline void add(ll x, ll y){
    edge[++tot] = (node){y, head[x]};
    head[x] = tot;
}

void tarjan(ll x){
    low[x] = dfn[x] = ++tim;
    stk[++top] = x;
    t[x] = 1;
    for(ll i = head[x]; i; i = edge[i].nxt){
        ll y = edge[i].v;
        if(!dfn[y])tarjan(y), low[x] = min(low[x], low[y]);
        else if(t[y]) low[x] = min(low[x], dfn[y]);
    }
    if(low[x] == dfn[x]){
        cnt++;
        do{
            siz[cnt]++;
            t[stk[top--]] = 0;
        }while(stk[top + 1] != x);
    }
}

inline ll qpow(ll a, ll b){
    ll res = 1;
    while(b){
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

signed main(){
    scanf("%lld", &n);
    for(ll i = 1, x; i <= n; ++i){
        scanf("%lld", &x);
        add(i, x);
    }
    for(ll i = 1; i <= n; ++i)
        if(!dfn[i]) tarjan(i);
    ll sum = 0, ans = 1;
    for(ll i = 1; i <= cnt; ++i)
        if(siz[i] > 1) ans = ans * (qpow(2, siz[i]) - 2 + mod % mod) % mod, sum += siz[i];
    ans = ans * qpow(2, n - sum) % mod;
    printf("%lld\n", ans);
    return 0;
}

End

标签:Directed,cnt,题解,ll,low,ans,Roads,mod,rightarrow
来源: https://www.cnblogs.com/xixike/p/15497096.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有