【题目大意】

给出$\{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 + , N = 2e5 + ;
const int mod = 1e9+; # define RG register
# define ST static inline int getint() {
int x = ; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * + ch - '', ch = getchar();
return x;
} int n, p[M], ans, fuckyou = ;
struct Graph {
int n, head[N], nxt[M], to[M], tot;
inline void set(int _n) {
n = _n; tot = ;
for (int i=; i<=n; ++i) head[i] = ;
}
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=; 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 = ; namespace FACINV {
int fac[N], inv[N], Inv[N]; inline int pwr(int a, int b, int P = mod) {
int ret = ;
while(b) {
if(b&) ret = 1ll * ret * a % P;
a = 1ll * a * a % P;
b >>= ;
}
return ret;
} inline void prepare() {
fac[] = ; inv[] = ;
for (int i=; i<=; ++i) fac[i] = 1ll * fac[i-] * i % mod;
inv[] = pwr(fac[], mod-);
for (int i=; i; --i) inv[i] = 1ll * inv[i+] * (i+) % mod;
for (int i=; i; --i) Inv[i+] = 1ll * inv[i+] * fac[i] % mod;
Inv[] = ;
} 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 = , 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] = ;
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=; i<=n; ++i) {
RG int fu = U.getf(p[i]), fv = U.getf(i);
if(fu == fv) inrings[i] = ;
else U.un(fu, fv);
}
for (int i=; i<=n; ++i) {
if(!inrings[i]) continue;
cn = ;
dfs_rings(i);
}
} inline void debug_rings() {
for (int i=; i<=rn; ++i) {
printf("num = %d\n ", i);
for (int j=; j<ring[i].size(); ++j)
cout << ring[i][j] << ' ';
cout << endl;
}
} inline void clear_rings() {
for (int i=; i<=rn; ++i) ring[i].clear();
for (int i=; i<=n; ++i) inrings[i] = vis[i] = deg[i] = ;
rn = ;
}
} 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=; 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=, 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=; i*i<=sz; ++i) {
if(sz % i == ) {
bool gg = ;
int d = sz/i;
for (int j=; j<sz; ++j) {
if(tem[j].hash != tem[(j-i+sz) % sz].hash) {
gg = ;
break;
}
}
if(!gg) {
fuckyou = 1ll * fuckyou * d % mod;
return ;
}
}
}
for (int i=sqrt(sz); i; --i) {
if(sz % i == ) {
bool gg = ;
int d = i;
for (int j=; j<sz; ++j) {
if(tem[j].hash != tem[(j-sz/i+sz) % sz].hash) {
gg = ;
break;
}
}
if(!gg) {
fuckyou = 1ll * fuckyou * d % mod;
return ;
}
}
}
return ;
} inline int mininum() {
int i=, j=, len = tem.size(), l;
while(i<len && j<len) {
for (l=; 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+;
else j = j+l+;
if(i == j) j = i+;
}
if(i<j) return i;
else return j;
} pa f[N], g[N];
int sze[N];
inline void dfs_tree(int x, int fa = , int d = ) {
sze[x] = ;
for (int i=G.head[x]; i; i=G.nxt[i]) {
if(G.to[i] == fa) continue;
dfs_tree(G.to[i], x, d+);
sze[x] += sze[G.to[i]];
}
tem.clear();
int sons = ;
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=; i<tem.size(); ++i) hsh = (hsh << ) ^ ((hsh & tem[i].hash) << ) + (( * hsh ^ tem[i].hash) >> ) ^ (tem[i].hash << );
gs(); hsh = hsh ^ HA[sze[x]] + HB[sons];
f[x] = pa(hsh, sze[x]);
} inline pa deal(vector<int> r) {
int SZ = ;
for (int i=; i<r.size(); ++i) {
int nx = r[(i- + r.size()) % r.size()];
dfs_tree(r[i], nx);
SZ += sze[r[i]];
}
tem.clear();
for (int i=; i<r.size(); ++i) tem.push_back(f[r[i]]);
// debug_tem();
int fro = mininum();
ull hsh = 19260817ull;
for (int i=; i<tem.size(); ++i) {
int j = (i + fro) % tem.size();
hsh = (hsh << ) ^ ((hsh & tem[j].hash) >> ) + ( * hsh & tem[j].hash) ^ (( * tem[j].hash ^ hsh) << ) ^ (tem[j].hash + );
}
hsh = hsh ^ HA[SZ];
gs2();
pa ret = pa(hsh, SZ);
return ret;
} inline void sol() {
n = getint(); G.set(n); ans = fac[n]; fuckyou = ;
for (int i=; i<=n; ++i) {
p[i] = getint();
G.add(p[i], i);
} find_rings();
// debug_rings(); for (int i=; i<=rn; ++i) g[i] = deal(ring[i]); tem.clear();
for (int i=; i<=rn; ++i) tem.push_back(g[i]);
gs();
ans = 1ll * ans * pwr(fuckyou, mod-) % mod;
--ans; if(ans < ) ans += mod;
cout << ans << endl;
clear_rings();
} inline ull irand() {
ull t = ;
for (int i=; i<=; ++i) t = (t<<) + rand();
return t;
} int main() {
freopen("langue.in", "r", stdin);
freopen("langue.out", "w", stdout);
prepare();
for (int i=; i<=n+n; ++i) HA[i] = irand(), HB[i] = irand();
int T; T = getint();
while(T--) sol();
return ;
}

我们直接找哈希最大值作为起点也行(可能出题人卡了最小值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 + , N = 2e5 + ;
const int mod = 1e9+; # define RG register
# define ST static inline int getint() {
int x = ; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * + ch - '', ch = getchar();
return x;
} int n, p[M], ans, fuckyou = ;
struct Graph {
int n, head[N], nxt[M], to[M], tot;
inline void set(int _n) {
n = _n; tot = ;
for (int i=; i<=n; ++i) head[i] = ;
}
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=; 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 = ; namespace FACINV {
int fac[N], inv[N], Inv[N]; inline int pwr(int a, int b, int P = mod) {
int ret = ;
while(b) {
if(b&) ret = 1ll * ret * a % P;
a = 1ll * a * a % P;
b >>= ;
}
return ret;
} inline void prepare() {
fac[] = ; inv[] = ;
for (int i=; i<=; ++i) fac[i] = 1ll * fac[i-] * i % mod;
inv[] = pwr(fac[], mod-);
for (int i=; i; --i) inv[i] = 1ll * inv[i+] * (i+) % mod;
for (int i=; i; --i) Inv[i+] = 1ll * inv[i+] * fac[i] % mod;
Inv[] = ;
} 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 = , 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] = ;
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=; i<=n; ++i) {
RG int fu = U.getf(p[i]), fv = U.getf(i);
if(fu == fv) inrings[i] = ;
else U.un(fu, fv);
}
for (int i=; i<=n; ++i) {
if(!inrings[i]) continue;
cn = ;
dfs_rings(i);
}
} inline void debug_rings() {
for (int i=; i<=rn; ++i) {
printf("num = %d\n ", i);
for (int j=; j<ring[i].size(); ++j)
cout << ring[i][j] << ' ';
cout << endl;
}
} inline void clear_rings() {
for (int i=; i<=rn; ++i) ring[i].clear();
for (int i=; i<=n; ++i) inrings[i] = vis[i] = deg[i] = ;
rn = ;
}
} 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=; 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=, 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=; i*i<=sz; ++i) {
if(sz % i == ) {
bool gg = ;
int d = sz/i;
for (int j=; j<sz; ++j) {
if(tem[j].hash != tem[(j-i+sz) % sz].hash) {
gg = ;
break;
}
}
if(!gg) {
fuckyou = 1ll * fuckyou * d % mod;
return ;
}
}
}
for (int i=sqrt(sz); i; --i) {
if(sz % i == ) {
bool gg = ;
int d = i;
for (int j=; j<sz; ++j) {
if(tem[j].hash != tem[(j-sz/i+sz) % sz].hash) {
gg = ;
break;
}
}
if(!gg) {
fuckyou = 1ll * fuckyou * d % mod;
return ;
}
}
}
return ;
} inline int mininum() {
ull mi = tem[].hash; int id = ;
for (int i=; 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 = , int d = ) {
sze[x] = ;
for (int i=G.head[x]; i; i=G.nxt[i]) {
if(G.to[i] == fa) continue;
dfs_tree(G.to[i], x, d+);
sze[x] += sze[G.to[i]];
}
tem.clear();
int sons = ;
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=; i<tem.size(); ++i) hsh = (hsh << ) ^ ((hsh & tem[i].hash) << ) + (( * hsh ^ tem[i].hash) >> ) ^ (tem[i].hash << );
gs(); hsh = hsh ^ HA[sze[x]] + HB[sons];
f[x] = pa(hsh, sze[x]);
} inline pa deal(vector<int> r) {
int SZ = ;
for (int i=; i<r.size(); ++i) {
int nx = r[(i- + r.size()) % r.size()];
dfs_tree(r[i], nx);
SZ += sze[r[i]];
}
tem.clear();
for (int i=; i<r.size(); ++i) tem.push_back(f[r[i]]);
// debug_tem();
int fro = mininum();
ull hsh = 19260817ull;
for (int i=; i<tem.size(); ++i) {
int j = (i + fro) % tem.size();
hsh = (hsh << ) ^ ((hsh & tem[j].hash) >> ) + ( * hsh & tem[j].hash) ^ (( * tem[j].hash ^ hsh) << ) ^ (tem[j].hash + );
}
hsh = hsh ^ HA[SZ];
gs2();
pa ret = pa(hsh, SZ);
return ret;
} inline void sol() {
n = getint(); G.set(n); ans = fac[n]; fuckyou = ;
for (int i=; i<=n; ++i) {
p[i] = getint();
G.add(p[i], i);
} find_rings();
// debug_rings(); for (int i=; i<=rn; ++i) g[i] = deal(ring[i]); tem.clear();
for (int i=; i<=rn; ++i) tem.push_back(g[i]);
gs();
ans = 1ll * ans * pwr(fuckyou, mod-) % mod;
--ans; if(ans < ) ans += mod;
cout << ans << endl;
clear_rings();
} inline ull irand() {
ull t = ;
for (int i=; i<=; ++i) t = (t<<) + rand();
return t;
} int main() {
freopen("langue.in", "r", stdin);
freopen("langue.out", "w", stdout);
prepare();
for (int i=; i<=n+n; ++i) HA[i] = irand(), HB[i] = irand();
int T; T = getint();
while(T--) sol();
return ;
}

「6月雅礼集训 2017 Day5」学外语的更多相关文章

  1. 「6月雅礼集训 2017 Day5」仰望星空

    [题目大意] 给你$n$个点,被一个半径为$R$的元圆划分成内(包含边界).外两个部分. 要连若干线,每个点只能连一条线,不存在重点和三点共线. 线只能连在内部点和外部点之间,线长度不超过$d$. 如 ...

  2. 「6月雅礼集训 2017 Day5」吃干饭

    [题目大意] 询问[L,R]中选若干个数异或起来得到的答案集合大小.多组数据. 对于50%的数据,$R - L \leq 10^4$ 对于100%的数据,$R - L \leq 10^{18}, T ...

  3. 「6月雅礼集训 2017 Day10」quote

    [题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. ...

  4. 「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)

    原题传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2687 [题目大意] 给出若干区间,求一个区间的大于等于2的子集,使得 |区间并| 和 | ...

  5. 「6月雅礼集训 2017 Day11」delight

    [题目大意] 有$n$天,每天能吃饭.睡觉.什么事也不干 每天吃饭的愉悦值为$e_i$,睡觉的愉悦值为$s_i$,什么都不干愉悦值为0. 要求每连续$k$天都要有至少$E$天吃饭,$S$天睡觉. 求最 ...

  6. 「6月雅礼集训 2017 Day11」jump

    [题目大意] 有$n$个位置,每个位置有一个数$x_i$,代表从$i$经过1步可以到达的点在$[\max(1, i-x_i), \min(i+x_i, n)]$中. 定义$(i,j)$的距离表示从$i ...

  7. 「6月雅礼集训 2017 Day11」tree

    [题目大意] 给出一棵带权树,有两类点,一类黑点,一类白点. 求切断黑点和白点间路径的最小代价. $n \leq 10^5$ [题解] 直接最小割能过..但是树形dp明显更好写 设$f_{x,0/1/ ...

  8. 「6月雅礼集训 2017 Day10」perm(CodeForces 698F)

    [题目大意] 给出一个$n$个数的序列$\{a_n\}$,其中有些地方的数为0,要求你把这个序列填成一个1到$n$的排列,使得: $(a_i, a_j) = 1$,当且仅当$(i, j) = 1$.多 ...

  9. 「6月雅礼集训 2017 Day8」route

    [题目大意] 给出平面上$n$个点,求一条连接$n$个点的不相交的路径,使得转换的方向符合所给长度为$n-2$的字符串. $n \leq 5000$ [题解] 考虑取凸包上一点,然后如果下一个是‘R' ...

随机推荐

  1. 2019寒假训练营第三次作业part1-网络空间安全概论第五章

    第五章 网络攻防技术 5.1 网路信息收集技术--网络踩点 黑客入侵系统之前,需要了解目标系统可能存在的: 管理上的安全缺陷和漏洞 网络协议安全缺陷与漏洞 系统安全缺陷与漏洞 黑客实施入侵过程中,需要 ...

  2. CCleaner专业版注册码

    下载软件安装之后: 1.断网 2.用户名:任意,注册码:C2YW-XZT7-A4SE-UD89-YZPC

  3. 阻塞 , 非阻塞 , 同步 ,异步 , I/O模型

    •阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待: •同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞:异步只需要I/O操作完成的通知,并不主动读写 ...

  4. 【.Net】浅谈C#中的值类型和引用类型

    在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为.如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常.很多人就是因为没有弄清楚这两个 ...

  5. 2011 Multi-University Training Contest 4 - Host by SDU

    A.Color the Simple Cycle(polya计数+字符串匹配) 此题的难点在于确定置换的个数,由a[i+k]=a[i], e[i+k]=e[i]联想到KMP. 于是把原串和原串扩大两倍 ...

  6. 【bzoj1202】[HNOI2005]狡猾的商人 带权并查集

    题目描述 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 Ai大于0时表 ...

  7. BZOJ4804 欧拉心算(莫比乌斯反演+欧拉函数+线性筛)

    一通套路后得Σφ(d)μ(D/d)⌊n/D⌋2.显然整除分块,问题在于怎么快速计算φ和μ的狄利克雷卷积.积性函数的卷积还是积性函数,那么线性筛即可.因为μ(pc)=0 (c>=2),所以f(pc ...

  8. Django Models相关

    Models的相关知识 1. AutoField:自增整数类型.根据 ID 自增长的 Int字段 2. IntegerField:整数类型 3. BigIntegerField:大整数类型.用于数值较 ...

  9. 【刷题】BZOJ 5154 [Tjoi2014]匹配

    Description 有N个单身的男孩和N个单身女孩,男孩i和女孩j在一起得到的幸福值为Hij.一个匹配即对这N个男孩女孩的安排: 每个男孩恰好有一个女朋友,每个女孩恰好有一个男朋友.一个匹配的幸福 ...

  10. [洛谷P3793]由乃救爷爷

    题目大意:有$n(n\leqslant2\times10^7)$个数,$m(m\leqslant2\times10^7)$个询问,每次询问问区间$[l,r]$中的最大值.保证数据随机 题解:分块,处理 ...