「6月雅礼集训 2017 Day5」学外语
2017-06-22 14:22
260 查看
【题目大意】
给出$\{P_i\}$,求经过以下操作后能够得到的不同序列个数:
第一步,选择$i, j$,交换$P_i,P_j$;第二步,把所有$P_x=i$的$P_x$变为$j$,把所有$P_x=j$的$P_x$变为$i$。
$n \leq 10^5$
【题解】
显然就是求
给出一个基环内向森林,求交换编号后,不同构的个数。
考虑什么时候会发生同构的情况。
容易发现,每当出现k个子树相同,或k个环套树相同,就有 k! 种同构方案。
那么我们只需要做一遍树哈希、环套树哈希(可以用最小表示法,或者按照哈希值最小作为起点)来处理。
代码好难写。。。
还被卡哈希了。。还没调处来qwq
upd: 是我找循环节错了
最小表示法:
View Code
给出$\{P_i\}$,求经过以下操作后能够得到的不同序列个数:
第一步,选择$i, j$,交换$P_i,P_j$;第二步,把所有$P_x=i$的$P_x$变为$j$,把所有$P_x=j$的$P_x$变为$i$。
$n \leq 10^5$
【题解】
显然就是求
给出一个基环内向森林,求交换编号后,不同构的个数。
考虑什么时候会发生同构的情况。
容易发现,每当出现k个子树相同,或k个环套树相同,就有 k! 种同构方案。
那么我们只需要做一遍树哈希、环套树哈希(可以用最小表示法,或者按照哈希值最小作为起点)来处理。
代码好难写。。。
还被卡哈希了。。还没调处来qwq
upd: 是我找循环节错了
最小表示法:
# include <map> # include <math.h> # include <vector> # include <stdio.h> # include <assert.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10, N = 2e5 + 10; const int mod = 1e9+7; # define RG register # define ST static inline int getint() { int x = 0; char ch = getchar(); while(!isdigit(ch)) ch = getchar(); while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x; } int n, p[M], ans, fuckyou = 1; struct Graph { int n, head , nxt[M], to[M], tot; inline void set(int _n) { n = _n; tot = 0; for (int i=1; i<=n; ++i) head[i] = 0; } inline void add(int u, int v) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; } inline void adde(int u, int v) { add(u, v), add(v, u); } }G; struct us { int fa , n; inline void set(int _n) { n = _n; for (int i=1; i<=n; ++i) fa[i] = i; } inline int getf(int x) { return fa[x] == x ? x : fa[x] = getf(fa[x]); } inline void un(int fu, int fv) { fa[fu] = fv; } }U; vector<int> ring ; int rn = 0; namespace FACINV { int fac , inv , Inv ; inline int pwr(int a, int b, int P = mod) { int ret = 1; while(b) { if(b&1) ret = 1ll * ret * a % P; a = 1ll * a * a % P; b >>= 1; } return ret; } inline void prepare() { fac[0] = 1; inv[0] = 1; for (int i=1; i<=100000; ++i) fac[i] = 1ll * fac[i-1] * i % mod; inv[100000] = pwr(fac[100000], mod-2); for (int i=99999; i; --i) inv[i] = 1ll * inv[i+1] * (i+1) % mod; for (int i=99999; i; --i) Inv[i+1] = 1ll * inv[i+1] * fac[i] % mod; Inv[1] = 1; } inline int gP(int x, int y) { assert(x >= y); return 1ll * fac[x] * inv[x-y] % mod; } inline int gC(int x, int y) { assert(x >= y); return 1ll * fac[x] * inv[x-y] % mod * inv[y] % mod; } } using namespace FACINV; namespace SOLVE_RINGS { bool inrings ; int c , cn = 0, deg ; bool vis ; inline void dfs_rings(int x) { if(vis[x]) { ++rn; for (int i=cn; i; --i) ring[rn].push_back(c[i]); return ; } c[++cn] = x; vis[x] = 1; for (int i=G.head[x]; i; i=G.nxt[i]) ++deg[x], dfs_rings(G.to[i]); --cn; } inline void find_rings() { U.set(n); for (int i=1; i<=n; ++i) { RG int fu = U.getf(p[i]), fv = U.getf(i); if(fu == fv) inrings[i] = 1; else U.un(fu, fv); } for (int i=1; i<=n; ++i) { if(!inrings[i]) continue; cn = 0; dfs_rings(i); } } inline void debug_rings() { for (int i=1; i<=rn; ++i) { printf("num = %d\n ", i); for (int j=0; j<ring[i].size(); ++j) cout << ring[i][j] << ' '; cout << endl; } } inline void clear_rings() { for (int i=1; i<=rn; ++i) ring[i].clear(); for (int i=1; i<=n; ++i) inrings[i] = vis[i] = deg[i] = 0; rn = 0; } } using namespace SOLVE_RINGS; struct pa { ull hash; int sz; pa() {} pa(ull hash, int sz) : hash(hash), sz(sz) {} }; ull HA[M], HB[M]; vector<pa> tem; inline void debug_tem() { for (int i=0; i<tem.size(); ++i) printf("hash = %lld, size = %d\n", tem[i].hash, tem[i].sz); } inline bool cmp_hash(pa a, pa b) { return a.hash < b.hash; } inline void gs(bool flag) { if(flag) sort(tem.begin(), tem.end(), cmp_hash); for (int i=0, j, t; i<tem.size(); i=j) { j = i; while(j<tem.size() && tem[j].hash == tem[i].hash) ++j; fuckyou = 1ll * fuckyou * fac[j-i] % mod; } } inline void gs2() { int sz = tem.size(); for (int i=1; i*i<=sz; ++i) { if(sz % i == 0) { bool gg = 0; int d = sz/i; for (int j=0; j<sz; ++j) { if(tem[j].hash != tem[(j-i+sz) % sz].hash) { gg = 1; break; } } if(!gg) { fuckyou = 1ll * fuckyou * d % mod; return ; } } } for (int i=sqrt(sz); i; --i) { if(sz % i == 0) { bool gg = 0; int d = i; for (int j=0; j<sz; ++j) { if(tem[j].hash != tem[(j-sz/i+sz) % sz].hash) { gg = 1; break; } } if(!gg) { fuckyou = 1ll * fuckyou * d % mod; return ; } } } return ; } inline int mininum() { ull mi = tem[0].hash; int id = 0; for (int i=1; i<tem.size(); ++i) if(tem[i].hash > mi) mi = tem[i].hash, id = i; return id; } pa f , g ; int sze ; inline void dfs_tree(int x, int fa = 0, int d = 0) { sze[x] = 1; for (int i=G.head[x]; i; i=G.nxt[i]) { if(G.to[i] == fa) continue; dfs_tree(G.to[i], x, d+1); sze[x] += sze[G.to[i]]; } tem.clear(); int sons = 0; for (int i=G.head[x]; i; i=G.nxt[i]) { if(G.to[i] == fa) continue; tem.push_back(f[G.to[i]]); ++ sons; } sort(tem.begin(), tem.end(), cmp_hash); ull hsh = 666623333ull; for (int i=0; i<tem.size(); ++i) hsh = (hsh << 13) ^ ((hsh & tem[i].hash) << 7) + ((67 * hsh ^ tem[i].hash) >> 13) ^ (tem[i].hash << 5); gs(0); hsh = hsh ^ HA[sze[x]] + HB[sons]; f[x] = pa(hsh, sze[x]); } inline pa deal(vector<int> r) { int SZ = 0; for (int i=0; i<r.size(); ++i) { int nx = r[(i-1 + r.size()) % r.size()]; dfs_tree(r[i], nx); SZ += sze[r[i]]; } tem.clear(); for (int i=0; i<r.size(); ++i) tem.push_back(f[r[i]]); // debug_tem(); int fro = mininum(); ull hsh = 19260817ull; for (int i=0; i<tem.size(); ++i) { int j = (i + fro) % tem.size(); hsh = (hsh << 7) ^ ((hsh & tem[j].hash) >> 2) + (103 * hsh & tem[j].hash) ^ ((233 * tem[j].hash ^ hsh) << 19) ^ (tem[j].hash + 233); } hsh = hsh ^ HA[SZ]; gs2(); pa ret = pa(hsh, SZ); return ret; } inline void sol() { n = getint(); G.set(n); ans = fac ; fuckyou = 1; for (int i=1; i<=n; ++i) { p[i] = getint(); G.add(p[i], i); } find_rings(); // debug_rings(); for (int i=1; i<=rn; ++i) g[i] = deal(ring[i]); tem.clear(); for (int i=1; i<=rn; ++i) tem.push_back(g[i]); gs(1); ans = 1ll * ans * pwr(fuckyou, mod-2) % mod; --ans; if(ans < 0) ans += mod; cout << ans << endl; clear_rings(); } inline ull irand() { ull t = 0; for (int i=0; i<=6; ++i) t = (t<<15) + rand(); return t; } int main() { freopen("langue.in", "r", stdin); freopen("langue.out", "w", stdout); prepare(); for (int i=1; i<=n+n; ++i) HA[i] = irand(), HB[i] = irand(); int T; T = getint(); while(T--) sol(); return 0; }
View Code
相关文章推荐
- 「6月雅礼集训 2017 Day5」吃干饭
- 「6月雅礼集训 2017 Day5」仰望星空
- 「6月雅礼集训 2017 Day4」暴力大神hxx
- 「6月雅礼集训 2017 Day10」quote
- 「6月雅礼集训 2017 Day2」A
- 「6月雅礼集训 2017 Day11」tree
- 「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)
- 「6月雅礼集训 2017 Day11」jump
- 「6月雅礼集训 2017 Day11」delight
- 「6月雅礼集训 2017 Day1」看无可看
- 「6月雅礼集训 2017 Day2」B
- 「6月雅礼集训 2017 Day8」infection
- 「6月雅礼集训 2017 Day7」回转寿司
- 「6月雅礼集训 2017 Day2」C
- 「6月雅礼集训 2017 Day8」gcd
- 「6月雅礼集训 2017 Day4」寻找天哥
- 「6月雅礼集训 2017 Day7」三明治
- 「6月雅礼集训 2017 Day8」route
- 「6月雅礼集训 2017 Day7」电报
- 「6月雅礼集训 2017 Day1」说无可说