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. Vue2源码解读 - 响应式原理及简单实现

    直接进入主题了,想必大家都知道实现vue响应式核心方法就是 Object.defineProperty,那就从它开始说 Object.defineProperty 缺点: 深度监听,需要递归到底,一次 ...

  2. SLAM名词介绍

    gauge freedom:测量自由度 degrees-of-freedom(DoF) 自由度 wide-baseline matches:宽基线匹配 宽基线匹配:从描绘同一场景的两个或多个图像中建立 ...

  3. 吴恩达深度学习课后习题第5课第1周第3小节: Jazz Improvisation with LSTM

    目录 Improvise a Jazz Solo with an LSTM Network Packages 1 - Problem Statement 1.1 - Dataset What are ...

  4. [敏捷软工团队博客]Beta阶段测试报告

    项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta阶段测试报告 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Bet ...

  5. hdu 1847 Good Luck in CET-4 Everybody! (简单博弈)

    题意: n张牌,双方轮流抓取.每人每次抓取的牌数必须是2的幂次(1,2,4,8...). 最后抓完的人胜. 思路 : 考虑剩3张牌,后手胜. 考虑3的倍数.假设先抓者当轮抓2x 张,2x %3等于1或 ...

  6. 力扣 - 剑指 Offer 66. 构建乘积数组

    题目 剑指 Offer 66. 构建乘积数组 思路1 按照一般的思路就是将所有的相乘,然后除以每一位数字就是答案,但是题目要求我们不能使用除法,因此我们会想到每次遍历到每个数字的时候,在遍历一遍数组, ...

  7. 【mysql3】我的大学teacher课程进行中|持续更新系列!

    1.做一下powerdesigner的画图 2.所有的创建表格 .....1 修改字段的数据类型:alter table 表名 modify 字段名 新数据类型; 修改字段名: alter table ...

  8. Leetcode 课程表 C++ 图的深度搜索和广度搜索练习

    广度搜索(degree) struct GraphNode{ int label; vector<GraphNode*> neighbours; GraphNode(int x):labe ...

  9. 常用的 21 条 Linux 命令,生产力必备

    一.文件和目录 1. cd命令 (它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径) cd /home 进入 '/ home' 目录 cd .. 返回上一级目录 c ...

  10. [linux]centos7.4安装nginx

    下载nginx wget http://nginx.org/download/nginx-1.5.6.tar.gz 解压包安装在/opt/nginx. 目录下, 1.安装gcc(centos 7之后一 ...