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. Mybatis 二级缓存应用 (21)

    [MyBatis 二级缓存] 概述:一级缓存作用域为同一个SqlSession对象,而二级缓存用来解决一级缓存不能夸会话共享,作用范围是namespace级,可以被多个SqlSession共享(只要是 ...

  2. 【Docker】(11)---Docker的网络概念

    一.实现原理 1.实现原理 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为C ...

  3. OO2020 助教工作总结

    1 我的初衷 这一学期的OO助教工作是我一段宝贵的经历,在其中我学习了很多.见识了很多,收获满满.当时报名OO的初衷主要有三方面.首先,我想说OO是我所上过的最好的一门课之一,这门课有这一套从理论讲授 ...

  4. 关于麦克风的参数介绍 - 驻极体麦克风(ECM)和硅麦(MEMS)

    1.麦克风的分类1.1.动圈式麦克风(Dynamic Micphone)原理:基本构造包含线圈.振膜.永久磁铁三部分.当声波进入麦克风,振膜受到声波的压力而产生振动,与振膜在一起的线圈则开始在磁场中移 ...

  5. Vagrant 搭建开发环境实践

    介绍 Development Environments Made Easy -官网标题 vagrant是一个命令行的虚拟机管理程序.用于简化搭建开发环境. vagrant使用ruby语言基于Chef ...

  6. MySql表、约束、视图

    MySql表.约束.视图 索引组织表 在InnoDB存储引擎中,表都是根据主键顺序组织存放的,这种存储方式的表成为索引组织表(index organized table). 每张表都有主键,如果创建表 ...

  7. Docker+nginx搭建tomcat集群

    1.环境准备: a.宿主机CentOS7 b.连接工具FinalShell c.镜像nginx1.20.1,tomcat (镜像拉取:docker pull 镜像名称) 2.创建nginx文件夹,to ...

  8. Linux使用ssh测试端口

    在windows上可以使用telnet客户端测试,在linux如果不方便安装telnet客户端的时候可以通关ssh来测试端口 具体命令如下 ssh -v -p 8080 root@59.207.252 ...

  9. Kioskcached(1)之 Memcached & Redis & Kioskcached 性能测试对比

    前言:本文仅仅是作者自己在学习过程中的一次实验而已,或许因为各种因素会导致实验结果与你之前的认知不太一样,因此请你带着批判的眼光看待本文(本文不具有实际环境的参考性). 一:测试目的 在了解了一些No ...

  10. idea连接数据库时区错误

    错误界面 IDEA连接mysql,地址,用户名,密码,数据库名,全都配置好了,点测试连接,咔!不成功! 界面是这样的, 翻译过来就是:服务器返回无效时区.进入"高级"选项卡,手动设 ...