Codeforces711D-Directed Roads(强连通分量+乘法原理)

来源:互联网 发布:80端口哪个运营商 编辑:程序博客网 时间:2024/06/15 23:44

题目链接

http://codeforces.com/contest/711/problem/D

思路

这道题的输入很神奇,由输入可以得出一个结论就是每个点最多只会有一条出边,因此每个点最多在一个环中。
然后对于一个环比如1 -> 2 -> 3 -> 1,其方案数是232,然后可以发现,对每一个独立的环,若有x个点,那么方案数就是2x2
对所有环,由输入得到的性质,因此结果直接相乘即可

代码

#include <iostream>#include <cstring>#include <stack>#include <vector>#include <set>#include <map>#include <cmath>#include <queue>#include <sstream>#include <iomanip>#include <fstream>#include <cstdio>#include <cstdlib>#include <climits>#include <deque>#include <bitset>#include <algorithm>using namespace std;#define PI acos(-1.0)#define LL long long#define PII pair<int, int>#define PLL pair<LL, LL>#define mp make_pair#define IN freopen("in.txt", "r", stdin)#define OUT freopen("out.txt", "wb", stdout)#define scan(x) scanf("%d", &x)#define scan2(x, y) scanf("%d%d", &x, &y)#define scan3(x, y, z) scanf("%d%d%d", &x, &y, &z)#define sqr(x) (x) * (x)const int maxn = 2 * 100000 + 5;const int mod = 1e9 + 7;vector<int> G[maxn];int n, scc_cnt, sccno[maxn], pre[maxn], lowlink[maxn], dfs_clock;stack<int> S;void dfs(int u) {    pre[u] = lowlink[u] = ++dfs_clock;    S.push(u);    for (int i = 0; i < G[u].size(); i++) {        int v = G[u][i];        if (!pre[v]) {            dfs(v);            lowlink[u] = min(lowlink[u], lowlink[v]);        } else if (!sccno[v]) {            lowlink[u] = min(lowlink[u], pre[v]);        }    }    if (lowlink[u] == pre[u]) {        scc_cnt++;        while (1) {            int x = S.top(); S.pop();            sccno[x] = scc_cnt;            if (x == u) break;        }    }}void find_scc() {    dfs_clock = scc_cnt = 0;    memset(sccno, 0, sizeof(sccno));    memset(pre, 0, sizeof(pre));    for (int i = 1; i <= n; i++) {        if (!sccno[i]) dfs(i);    }}LL power(int x) {    LL ans = 1;    for (int i = 1; i <= x; i++) (ans <<= 1) %= mod;    return ans - 2;}int main() {    scan(n);    for (int i = 1; i <= n; i++) {        int x;        scan(x);        G[i].push_back(x);    }    find_scc();    int cnt[maxn];    memset(cnt, 0, sizeof(cnt));    for (int i = 1; i <= n; i++) cnt[sccno[i]]++;    LL res = 1;    for (int i = 1; i <= n; i++) {        LL x = (LL)(cnt[i]);        if (!x) break;        if (x >= 2) ((res *= power(x))) %= mod;        else if (x == 1) (res *= 2) %= mod;    }    printf("%I64d\n", res);    return 0;}
0 0
原创粉丝点击