Problem Statement | |
Hero has just constructed a very specific graph. He started with n isolated vertices, labeled 0 through n-1. For each vertex i Hero then chose a vertex a[i] (other than i) and he added an edge that connected i and a[i]. This way he created a graph with n vertices and n edges. Note that if a[x]=y and a[y]=x, the vertices x and y were connected by two different edges. Hero now wants to perform the following procedure:
|
题意是说给出一个数组a,a[i]=j表示i到j有一条边。然后选定一个点的集合,这个集合中所有点a[x]=y的边都去掉,并把这些点都连接向点n。如果最终形成的图还是联通,那么就是好集合。问这样的集合有多少个。
和CF22E很像。。。如果每一个联通分量里面点的个数为x,尾巴上的点的个数为y,那么这块的集合的个数为2^x-2^y。把每一部分乘到一起。
代码:
#pragma warning(disable:4996)
#include <fstream>
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define eps 1e-12
#define INF 0x3f3f3f3f
#define mem(a, b) memset(a, b, sizeof(a))
#define pper(i,n,m) for(int i = n;i >= m; i--)
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))
#define mp make_pair
#define ff first
#define ss second
#define pb push_back
const int maxn = 500005, maxd = 18;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);
ll vis[maxn], cnt[maxn];
set<int>u;
class Sunnygraphs2
{
public:
long long count(vector <int> a)
{
ll res = 1;
int sz = a.size();
int uni = 1;
int i, j, k;
u.clear();
u.insert(0);
mem(cnt, 0);
mem(vis, -1);
for (i = 0; i < sz; i++)
{
ll now = 1;
int x = i;
if (vis[x] == -1)
{
while (vis[x] == -1)
{
vis[x] = i;
now <<= 1;
cnt[x] = now;
x = a[x];
}
if (u.find(vis[x]) != u.end())
{
u.insert(i);
}
else
{
uni = 0;
}
if (vis[x] == i)
{
res = res*(now - (cnt[x] >> 1));
}
else
{
res = res*now;
}
}
}
if (uni == 1)
res++;
return res;
}
};