arc062 F - Painting Graphs with AtCoDeer

F - Painting Graphs with AtCoDeer

不在环上的边是平凡的。

一个单独的环方案统计显然是直接用burnside引理统计即可,问题在于多个环嵌套。

此时会发现,多个环嵌套时,这些环包含的边颜色可以任意排列,可以构造性地不严谨证明一下,两个环A,B相交,设一个相交边为e,则B需要的边可以通过e先都放到A里,然后不断旋转A,把B所需的下一个边转到e,然后B拿走这条边,只到B构建完成(不包括e本身所需),然后再考虑类似地构建A。

判环是否无嵌套,可以DCC缩点,然后看点双中的点彼此间边数是否等于点数,这题数据范围唬人...

#include
#define pii pair
#define fi first
#define sc second
#define pb push_back
#define ll long long
#define trav(v,x) for(auto v:x)
#define all(x) (x).begin(), (x).end()
#define VI vector
#define VLL vector
#define pll pair
#define double long double
//#define int long long
using namespace std;
const int N = 1e6 + 100;
const int inf = 1e9;
//const ll inf = 1e18;
const ll mod = 1e9 + 7;

#ifdef LOCAL
void debug_out(){cerr << endl;}
template
void debug_out(Head H, Tail... T)
{
	cerr << " " << to_string(H);
	debug_out(T...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

ll C[510][510];

void sol()
{
	C[0][0] = 1;
	for(int i = 1; i <= 500; i++)
	{
		C[i][0] = 1;
		for(int j = 1; j <= 500; j++)
		{
			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
		}
	}
	int n, m, num;
	cin >> n >> m >> num;
	vector adj(n);
	for(int i = 0; i < m; i++)
	{
		int x, y;
		cin >> x >> y;
		--x, --y;
		adj[x].pb(y);
		adj[y].pb(x);
	}
	VI low(n), dfn(n);
	vector stk;
	vector> DCC;
	int tim = 0;
	function dfs = [&](int x, int ff)
	{
		dfn[x] = ++tim;
		low[x] = tim;
		bool skp = 0;
		trav(v, adj[x])
		{
			if(v == ff && !skp)
			{
				skp = 1;
				continue;
			}
			if(!dfn[v])
			{
				stk.pb(pii(x, v));
				dfs(v, x);
				low[x] = min(low[x], low[v]);
				if(low[v] >= dfn[x])
				{
					vector cur;
					while(stk.back() != pii(x, v))
						cur.pb(stk.back()), stk.pop_back();
					stk.pop_back();
					cur.pb(pii(x, v));
					DCC.pb(cur);
				}
			}
			else low[x] = min(low[x], dfn[v]);
		}
	};
	auto qpow = [&](ll x, ll y)
	{
		ll res = 1;
		while(y)
		{
			if(y & 1)
				res = res * x % mod;
			x = x * x % mod;
			y >>= 1;
		}
		return res;
	};
	ll ans = 1;
	for(int i = 0; i < n; i++)
	{
		if(dfn[i])
			continue;
		stk.clear();
		DCC.clear();
		dfs(i, -1);
		trav(buk, DCC)
		{
			if(buk.size() == 1)
			{
				ans = ans * num % mod;
				continue;
			}
			set st;
			trav(v, buk)
			{
				st.insert(v.fi);
				st.insert(v.sc);
			}
			int t = 0;
			trav(u, st)
			{
				trav(v, adj[u])
				{
					if(st.find(v) != st.end())
						++t;
				}
			}
			t /= 2;
			if((int)st.size() == t)
			{
				ll res = 0;
				for(int j = 0; j < t; j++)
					res = (res + qpow(num, __gcd(j, t))) % mod;
				ans = ans * res % mod * qpow(t, mod - 2) % mod;
			}
			else
			{
				ans = ans * C[num + t - 1][t] % mod;
			}
		}
	}
	cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
//	int tt;
//	cin >> tt;
//	while(tt--)
		sol();
}

你可能感兴趣的:(刷题集,c++,算法,题解)