您的位置:首页 > 其它

[CF711D]Directed Roads(强联通分量,计数)

2016-08-29 23:36 387 查看
题目链接:http://codeforces.com/contest/711/problem/D

题意:n个点n条边的有向图,每个点都指向另外一个点,要翻转其中的几条边,问有多少种翻转方式可以使这张图没有环存在。

可以先求强联通分量,由于题目的特殊性,每个点只有一个出边,所以加入一个强联通分量至少有两个点,则每一个强联通分量中必定有且仅有只有一个环。我们考虑如何翻转这个环内的边,使得生成的数量一共有C(x,1)+C(x,2)+...+C(x,x)=2^x-1种,除去全部翻转的C(x,x),则还剩下2^x-2种。则所有点数大于2强联通分量内一共有Σ(2^xi-2)种。

再考虑一个出边的强联通分量,无论如何翻转都是没有问题的,则一共可以翻转2^y次。

则总共可以翻转(Σ(2^xi-2))*2^y次。

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
using namespace std;
#define fr first
#define sc second
#define cl clear
#define BUG puts("here!!!")
#define W(a) while(a--)
#define pb(a) push_back(a)
#define Rint(a) scanf("%d", &a)
#define Rll(a) scanf("%I64d", &a)
#define Rs(a) scanf("%s", a)
#define Cin(a) cin >> a
#define FRead() freopen("in", "r", stdin)
#define FWrite() freopen("out", "w", stdout)
#define Rep(i, len) for(int i = 0; i < (len); i++)
#define For(i, a, len) for(int i = (a); i < (len); i++)
#define Cls(a) memset((a), 0, sizeof(a))
#define Clr(a, x) memset((a), (x), sizeof(a))
#define Full(a) memset((a), 0x7f7f7f, sizeof(a))
#define lrt rt << 1
#define rrt rt << 1 | 1
#define pi 3.14159265359
#define RT return
#define lowbit(x) x & (-x)
#define onecnt(x) __builtin_popcount(x)
typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;
typedef pair<int, int> pii;
typedef pair<string, int> psi;
typedef pair<LL, LL> pll;
typedef map<string, int> msi;
typedef vector<int> vi;
typedef vector<LL> vl;
typedef vector<vl> vvl;
typedef vector<bool> vb;

const int maxn = 200200;
const LL mod = 1e9+7;
LL ret;

typedef struct Edge {
int u;
int v;
int next;
Edge() { next = -1; }
}Edge;

int head[maxn], ecnt;
Edge edge[maxn];
int n, m;

int bcnt, dindex;
int dfn[maxn], low[maxn];
int stk[maxn], top;
int belong[maxn];
int in[maxn], out[maxn];
bool instk[maxn];
int cnt[maxn];

void init() {
memset(edge, 0, sizeof(edge));
memset(head, -1, sizeof(head));
memset(instk, 0, sizeof(instk));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(belong, 0, sizeof(belong));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
ecnt = top = bcnt = dindex = 0;
}

void adde(int uu, int vv) {
edge[ecnt].u = uu;
edge[ecnt].v = vv;
edge[ecnt].next = head[uu];
head[uu] = ecnt++;
}

void tarjan(int u) {
int v = u;
dfn[u] = low[u] = ++dindex;
stk[++top] = u;
instk[u] = 1;
for(int i = head[u]; ~i; i=edge[i].next) {
v = edge[i].v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instk[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
bcnt++;
do {
v = stk[top--];
instk[v] = 0;
belong[v] = bcnt;
cnt[bcnt]++;
} while(v != u);
}
}

LL quickmul(LL x, LL n) {
LL ans = 1;
while(n) {
if(n & 1) ans = (ans * x) % mod;
x = x * x % mod;
n >>= 1;
}
return ans;
}

int main() {
// FRead();
while(~Rint(n)) {
ret = 1; Cls(cnt);
init();
int v;
For(i, 1, n+1) {
Rint(v);
adde(i, v);
}
For(i, 1, n+1) if(!dfn[i]) tarjan(i);
LL tmp = 0;
For(i, 1, bcnt+1) {
if(cnt[i] > 1) {
ret = (ret * (quickmul(2, cnt[i])-2+mod))%mod;
tmp = (tmp + cnt[i]) % mod;
}
}
ret = (ret * quickmul(2, n-tmp)) % mod;
cout << ret << endl;
}
RT 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: