Codeforces 题面传送门 & 洛谷题面传送门

神仙题。在 AC 此题之前,此题已经在我的任务计划中躺了 5 个月的灰了。

首先考虑这个最短距离是什么东西,有点常识的人(大雾)应该知道,对于一个排列 \(p\) 而言,通过交换两个元素使其变成 \(1,2,3,4,\cdots,n\) 的最少步数等于 \(n\) 减去该排列中置换环的个数,因此对于两个排列 \(a,b\) 而言,将 \(a\) 变成 \(b\) 所需的最少步数即是在所有 \(a_i\) 与 \(b_i\) 之间连 \(a_i\to b_i\) 的边后,\(n\) 减去置换环的个数,因此我们只用考虑有多少个排列对 \((a,b)\) 满足其置换环个数为 \(k,k\in[1,n]\cap\mathbb{Z}\) 即可。

考虑对于某个下标 \(i\),已经确定的位置可能有以下四种:

  • \((a_i,b_i)\)
  • \((a_i,0)\)
  • \((0,b_i)\)
  • \((0,0)\)

对于第一种情况我们可以直接建立一个并查集维护连通性,然后将 \(a_i,b_i\) 合并,如果已经连成环了就令置换环个数 \(+1\) 然后忽略这些边。这样就只剩 \((a_i,0),(0,b_i),(0,0)\) 这三种边了,但是对于中间两种情况,当 \(a_i=b_i\) 时会额外多一些限制,因此考虑对于形如 \((x,0),(0,x)\) 的边我们干脆将它们合并为 \((0,0)\),这样任意两条边的端点都不同了,我们考虑对这三种边分别讨论,假设这三种边的个数分别为 \(x,y,z\),注意到在连边的过程中有个性质:

Observation. 当我们将 \((0,b_i)\) 与 \((0,0)\) 合并时还是会得到 \((0,0)\),即 \((0,0)\) 边的个数在与第二、三类边连边的过程中不会发生任何变化。

因此我们考虑以下过程:

  • 所有第二类边与某些第四类边连接,形成 \(p\) 个置换环
  • 所有第三类边与某些第四类边连接,形成 \(q\) 个置换环
  • 将剩余的 \(z\) 个第四类边连接,形成 \(r\) 个置换环

受到这个思想的启发,我们考虑将三步分别进行并将它们的方案乘起来。考虑设 \(f_p,g_q,h_r\) 分别表示第一、二、三步得到 \(p,q,r\) 的方案数。求 \(f_p\) 显然我们可以枚举有多少个二类边形成了环,设为 \(c\),那么剩余的二类边肯定会转化为第四类边,方案数 \(\begin{bmatrix}c\\p\end{bmatrix}·\dbinom{x}{c}·(z+x-c-1)^{\underline{x-c}}\),稍微解释一下这个式子,\(\begin{bmatrix}c\\p\end{bmatrix}\) 表示 \(c\) 条边形成 \(p\) 个置换环的方案数,\(\dbinom{x}{c}\) 表示从 \(x\) 条边中选出 \(c\) 条的方案数,\((z+x-c-1)^{\underline{x-c}}\) 表示处理剩余 \(x-c\) 条二类边的方案数,第一条边可以与剩余 \(z+x-c-1\) 条边匹配,而每处理完一条边后决策就少一个,因此方案数是一个下降幂的形式。\(g_q\) 也同理,\(h_r\) 就直接 \(\begin{bmatrix}z\\r\end{bmatrix}z!\) 即可,最后将三个数组求个 convolution 即可。

由于此题数据范围小得离谱,可以暴力递推第一类斯特林数+暴力卷积。

const int MAXN=250;
const int MOD=998244353;
int n,a[MAXN+5],b[MAXN+5],c[2][2],fa[MAXN+5],cnt=0,ans[MAXN+5];
int find(int x){return (!fa[x])?x:fa[x]=find(fa[x]);}
void merge(int x,int y){x=find(x);y=find(y);(x==y)?(cnt++):(fa[x]=y);}
int fac[MAXN+5],ifac[MAXN+5],s[MAXN+5][MAXN+5];
void init_fac(int n){
for(int i=(fac[0]=ifac[0]=ifac[1]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
for(int i=(s[0][0]=1);i<=n;i++) for(int j=1;j<=i;j++)
s[i][j]=(s[i-1][j-1]+1ll*(i-1)*s[i-1][j])%MOD;
}
void calc(int *f,int a,int b){
if(!b){
for(int i=0;i<=a;i++) f[i]=s[a][i];
return;
} for(int i=0;i<=a;i++) for(int j=i;j<=a;j++)
f[i]=(f[i]+1ll*fac[a]*ifac[j]%MOD*ifac[a-j]%MOD*
s[j][i]%MOD*fac[a+b-j-1]%MOD*ifac[b-1])%MOD;
}
int f1[MAXN+5],f2[MAXN+5],f3[MAXN+5],tmp[MAXN+5];
int in[MAXN+5],out[MAXN+5];
int main(){
scanf("%d",&n);init_fac(MAXN);
memset(in,0xff,sizeof(in));memset(out,0xff,sizeof(out));
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++) if(a[i]&&b[i]) merge(a[i],b[i]);
for(int i=1;i<=n;i++) in[b[i]]=a[i],out[a[i]]=b[i];
for(int i=1;i<=n;i++) if(!~in[i]&&~out[i]){
int cur=i;
while(cur&&~out[cur]) cur=out[cur];
if(!cur) ++c[0][1];
}
for(int i=1;i<=n;i++) if(~in[i]&&!~out[i]){
int cur=i;
while(cur&&~in[cur]) cur=in[cur];
if(!cur) ++c[1][0];
}
for(int i=1;i<=n;i++) if(!a[i]&&!b[i]) c[0][0]++;
for(int i=1;i<=n;i++) if(!in[i]){
int cur=i;
while(cur&&~out[cur]) cur=out[cur];
if(!cur) ++c[0][0];
} //printf("%d %d %d\n",c[0][0],c[1][0],c[0][1]);
calc(f1,c[1][0],c[0][0]);calc(f2,c[0][1],c[0][0]);
for(int i=0;i<=c[0][0];i++) f3[i]=1ll*fac[c[0][0]]*s[c[0][0]][i]%MOD;
// for(int i=0;i<=c[1][0];i++) printf("%d%c",f1[i]," \n"[i==c[1][0]]);
// for(int i=0;i<=c[0][1];i++) printf("%d%c",f2[i]," \n"[i==c[0][1]]);
// for(int i=0;i<=c[0][0];i++) printf("%d%c",f3[i]," \n"[i==c[0][0]]);
for(int i=0;i<=c[1][0];i++) for(int j=0;j<=c[0][1];j++)
tmp[i+j]=(tmp[i+j]+1ll*f1[i]*f2[j])%MOD;
for(int i=0;i<=c[1][0]+c[0][1];i++) for(int j=0;j<=c[0][0];j++)
ans[i+j]=(ans[i+j]+1ll*tmp[i]*f3[j])%MOD;
for(int i=0;i<n;i++) printf("%d%c",(n-i-cnt<0)?0:ans[n-i-cnt]," \n"[i==n-1]);
return 0;
}

Codeforces 715E - Complete the Permutations(第一类斯特林数)的更多相关文章

  1. CF715E Complete the Permutations(第一类斯特林数)

    题目 CF715E Complete the Permutations 做法 先考虑无\(0\)排列的最小花费,其实就是沿着置换交换,花费:\(n-\)环个数,所以我们主要是要求出规定环的个数 考虑连 ...

  2. 【CF715E】Complete the Permutations 第一类斯特林数

    题目大意 有两个排列 \(p,q\),其中有一些位置是空的. 你要补全这两个排列. 定义 \(s(p,q)\) 为 每次交换 \(p\) 中的两个数,让 \(p=q\) 的最小操作次数. 求 \(s( ...

  3. @codeforces - 715E@ Complete the Permutations

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定两个排列 p, q,他们中的有些位置被替换成了 0. 两个排 ...

  4. 【CF715E】Complete the Permutations(容斥,第一类斯特林数)

    [CF715E]Complete the Permutations(容斥,第一类斯特林数) 题面 CF 洛谷 给定两个排列\(p,q\),但是其中有些位置未知,用\(0\)表示. 现在让你补全两个排列 ...

  5. 【UVA 11077】 Find the Permutations (置换+第一类斯特林数)

    Find the Permutations Sorting is one of the most used operations in real life, where Computer Scienc ...

  6. UVA11077 Find the Permutations —— 置换、第一类斯特林数

    题目链接:https://vjudge.net/problem/UVA-11077 题意: 问n的全排列中多有少个至少需要交换k次才能变成{1,2,3……n}. 题解: 1.根据过程的互逆性,可直接求 ...

  7. CF960G Bandit Blues 第一类斯特林数+分治+FFT

    题目传送门 https://codeforces.com/contest/960/problem/G 题解 首先整个排列的最大值一定是 \(A\) 个前缀最大值的最后一个,也是 \(B\) 个后缀最大 ...

  8. 【HDU 4372】 Count the Buildings (第一类斯特林数)

    Count the Buildings Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...

  9. 【组合数学:第一类斯特林数】【HDU3625】Examining the Rooms

    Examining the Rooms Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

随机推荐

  1. 【c++ Prime 学习笔记】第7章 类

    类的基本思想是数据抽象和封装 数据分离抽象是一种依赖于接口和实现分离的编程/设计技术.接口包括用户能执行的操作,实现包括类的数据成员.接口实现的函数体.定义类所需的各种私有函数 封装实现了类的接口和实 ...

  2. [对对子队]会议记录4.18(Scrum Meeting9)

    今天已完成的工作 何瑞 ​ 工作内容:修复了一些关卡1的bug ​ 相关issue:搭建关卡1 ​ 相关签入:4.18签入1 4.18签入2 梁河览 ​ 工作内容:实现了音量控制,添加了BGM ​ 相 ...

  3. 2021.8.13考试总结[NOIP模拟38]

    T1 a 入阵曲.枚举矩形上下界,之后从左到右扫一遍.用树状数组维护前缀和加特判可以$A$,更保险要脸的做法是双指针扫,因为前缀和单调不减. $code:$ 1 #include<bits/st ...

  4. 计算机网络传输层之TCP可靠传输

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/105524592 学习课程:<2019王道考研计算机网络> 学习目的 ...

  5. 碰撞的蚂蚁 牛客网 程序员面试金典 C++ Java Python

    碰撞的蚂蚁 牛客网 程序员面试金典 C++ Java Python 题目描述 在n个顶点的多边形上有n只蚂蚁,这些蚂蚁同时开始沿着多边形的边爬行,请求出这些蚂蚁相撞的概率.(这里的相撞是指存在任意两只 ...

  6. 51nod_1001 数组中和等于K的数对(二分)

    题意: 给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K的数对.例如K = 8,数组A:{-1,6,5,3,4,2,9,0,8},所有和等于8的数对包括(-1,9 ...

  7. hdu 1501 Zipper(DP)

    题意: 给三个字符串str1.str2.str3 问str1和str2能否拼接成str3.(拼接的意思可以互相穿插) 能输出YES否则输出NO. 思路: 如果str3是由str1和str2拼接而成,s ...

  8. docker创建本地主机实例Virtualbox 驱动出错

    宿主机系统:Centos7 64位 创建主机实例Virtualbox 命令:docker-machine create -d virtualbox test 连接centos工具:Finalshell ...

  9. laravel路由导出和参数加密

    路由导出 代码位置:\vendor\laravel\framework\src\Illuminate\Foundation\Console\RouteListCommand.php protected ...

  10. 交换机 & 路由基础

    以太网帧结构 Ethernet II帧结构 Ethernet_II帧类型值大于等于1536(0×0600) 以太网帧结构的长度在64-1518字节之间 帧各字段说明 目的MAC地址(DMAC):接收方 ...