• Codeforces Round #369 (Div. 2) D. Directed Roads —— DFS找环 + 快速幂


    题目链接:http://codeforces.com/problemset/problem/711/D


    D. Directed Roads
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    ZS the Coder and Chris the Baboon has explored Udayland for quite some time. They realize that it consists of n towns numbered from 1 to n.

    There are n directed roads in the Udayland. i-th of them goes from town i to some other town ai (ai ≠ i). ZS the Coder can flip the direction of any road in Udayland, i.e. if it goes from town A to town B before the flip, it will go from town B to town A after.

    ZS the Coder considers the roads in the Udayland confusing, if there is a sequence of distinct towns A1, A2, ..., Ak (k > 1) such that for every 1 ≤ i < k there is a road from town Ai to town Ai + 1 and another road from town Ak to town A1. In other words, the roads are confusing if some of them form a directed cycle of some towns.

    Now ZS the Coder wonders how many sets of roads (there are 2n variants) in initial configuration can he choose to flip such that after flipping each road in the set exactly once, the resulting network will not be confusing.

    Note that it is allowed that after the flipping there are more than one directed road from some town and possibly some towns with no roads leading out of it, or multiple roads between any pair of cities.

    Input

    The first line of the input contains single integer n (2 ≤ n ≤ 2·105) — the number of towns in Udayland.

    The next line contains n integers a1, a2, ..., an (1 ≤ ai ≤ n, ai ≠ i)ai denotes a road going from town i to town ai.

    Output

    Print a single integer — the number of ways to flip some set of the roads so that the resulting whole set of all roads is not confusing. Since this number may be too large, print the answer modulo 109 + 7.

    Examples
    input
    3
    2 3 1
    
    output
    6
    
    input
    4
    2 1 1 1
    
    output
    8
    
    input
    5
    2 4 2 5 3
    
    output
    28
    
    Note

    Consider the first sample case. There are 3 towns and 3 roads. The towns are numbered from 1 to 3 and the roads are  initially. Number the roads 1 to 3 in this order.

    The sets of roads that ZS the Coder can flip (to make them not confusing) are {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}. Note that the empty set is invalid because if no roads are flipped, then towns 1, 2, 3 is form a directed cycle, so it is confusing. Similarly, flipping all roads is confusing too. Thus, there are a total of 6 possible sets ZS the Coder can flip.

    The sample image shows all possible ways of orienting the roads from the first sample such that the network is not confusing.

    题解:

    1.根据题意, n个点共有n条边。那么表明每个连通块中, 有且仅有一个环, 且这个环可能还有一些“线丝”挂在上面。

    2.首先对于一个连通块而言, 可分为环部分和线丝部分:对于环部分,如果有k个点, 那么有(1<<k)-2种情况可以去环。(-2是减去所有都flip或者所有都不flip这两种情况,因为这两种情况都不能 去环), 对于线丝部分, 他们的状态对环没有影响,假设线丝有t个点,那么状态数为1<<t。

    最后将每个连通块的环部分和线丝部分的状态数相乘, 即为答案。


    找环问题:

    1.group[]数组记录当前点时是在哪一次的dfs中访问到的。vis[]记录当前点在这次dfs中是第几个被访问的元素。

    2.在dfs的过程中, 当遇到被访问过的元素时: 如果它的group[i]为这次dfs所标记的, 那么表明这次dfs构成了环; 如果group[i]为之前dfs所标记的, 那么表明这次dfs出来的是线丝(遇到的连通块必定有环。因为:假设无环,那么就可以dfs出环了,说明假设不成立)。



    代码如下:

     1 #include<bits/stdc++.h>
     2 #define ms(a, b)  memset((a), (b), sizeof(a))
     3 using namespace std;
     4 typedef long long LL;
     5 const double eps = 1e-6;
     6 const int INF = 2e9;
     7 const LL LNF = 9e18;
     8 const int mod = 1e9+7;
     9 const int maxn = 2e5+10;
    10 
    11 int n, a[maxn];
    12 int vis[maxn], group[maxn];
    13 LL ans;
    14 
    15 LL qpow(LL x, LL y)
    16 {
    17     LL s = 1;
    18     while(y)
    19     {
    20         if(y&1) s = (s*x)%mod;
    21         x = (x*x)%mod;
    22         y >>= 1;
    23     }
    24     return s;
    25 }
    26 
    27 void dfs(int k, int id, int cnt)  //dfs出环, 或者dfs出线丝
    28 {
    29     vis[k] = cnt;
    30     group[k] = id;
    31 
    32     if(vis[a[k]]) //遇到了被访问过的元素
    33     {
    34         if(group[a[k]]==id)  //dfs出环
    35         {
    36             ans *= qpow(2,cnt-vis[a[k]]+1)-2, ans %= mod;  //环的部分
    37             ans *= qpow(2, vis[a[k]]-1), ans %= mod;  // 环之外的那条线
    38         }
    39         else ans *= qpow(2,cnt), ans %= mod;  //dfs出线丝
    40     }
    41     else dfs(a[k], id, cnt+1);
    42 }
    43 
    44 int main()
    45 {
    46     scanf("%d",&n);
    47     for(int i = 1; i<=n; i++)
    48         scanf("%d",&a[i]);
    49 
    50     ans = 1;
    51     ms(vis,0);
    52     ms(group,0);
    53     for(int i = 1; i<=n; i++)
    54         if(!vis[i])
    55             dfs(i,i,1);
    56 
    57     printf("%lld
    ", ans);
    58 }
    View Code
  • 相关阅读:
    四则运算
    屏蔽恶意IP
    Vue企业级优雅实战05-框架开发01-登录界面
    Vue企业级优雅实战04-组件开发01-SVG图标组件
    Vue企业级优雅实战03-准备工作04-全局设置
    Vue企业级优雅实战02-准备工作03-提交 GIT 平台
    802.11ax TWT
    leetcode338
    春招实习面经(已拿阿里/腾讯/亚马逊)
    leetcode weekly contest138
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538694.html
Copyright © 2020-2023  润新知