【题目大意】
给出${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[N], 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], 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[N]; int rn = 0; namespace FACINV { int fac[N], inv[N], Inv[N]; 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[N]; int c[N], cn = 0, deg[N]; bool vis[N]; 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 ", 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 ", 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() { int i=0, j=1, len = tem.size(), l; while(i<len && j<len) { for (l=0; l<len; ++l) if(tem[(i+l)%len].hash != tem[(j+l)%len].hash) break; if(l>len) break; if(tem[(i+l)%len].hash > tem[(j+l)%len].hash) i = i+l+1; else j = j+l+1; if(i == j) j = i+1; } if(i<j) return i; else return j; } pa f[N], g[N]; int sze[N]; 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[n]; 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; }
我们直接找哈希最大值作为起点也行(可能出题人卡了最小值23333)
# 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[N], 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], 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[N]; int rn = 0; namespace FACINV { int fac[N], inv[N], Inv[N]; 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[N]; int c[N], cn = 0, deg[N]; bool vis[N]; 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 ", 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 ", 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[N], g[N]; int sze[N]; 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[n]; 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; }