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. .NET 分布式系统架构(有转载部分)

    一.设计目的 搭建一个大型平台需要综合考虑很多方面,不单纯是软件架构,还包括网络和硬件设备等.由于现代大部分应用建设都面临用户多.高并发.高可用的需求,传统软件架构已不能满足需求,需要支持分布式软件架 ...

  2. DDD领域驱动设计-概述-Ⅰ

     如果我看得更远,那是因为我站在巨人的肩膀上.(If I have seen further it is by standing on ye shoulder of Giants.)         ...

  3. “妈妈再也不用担心我忘交作业了!”——记2020BUAA软工团队项目选择

    写在前面 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 团队项目选择 项目简介 项目名称:北航学生资源整合和作业提醒平台 项目内容: 设计实现一 ...

  4. dwr简单应用及一个反向ajax消息推送

    由于项目中最近需要用到dwr实现一些功能,因此在网上和dwr官网上找了一些资料进行学习.在此记录一下.(此处实现简单的dwr应用和dwr消息反向推送) 一.引入dwr的包 <dependency ...

  5. 用python检查矩阵的计算

    鉴于最近复习线性代数计算量较大,且1800答案常常忽略一些逆阵.行列式的计算答案,故用Python写出矩阵的简单计算程序,便于检查出错的步骤. 1.行列式 可自行更改阶数 from numpy imp ...

  6. Python3 TypeError: initial_value must be str or None, not bytes

    response.read() returns an instance of bytes while StringIO is an in-memory stream for text only. Us ...

  7. 一步一步学ROP之linux_x64篇(蒸米spark)

    目录 一步一步学ROP之linux_x64篇(蒸米spark) 0x00 序 0x01 Memory Leak & DynELF - 在不获取目标libc.so的情况下进行ROP攻击 0x02 ...

  8. ffmpeg第7篇:数据流选择神器-map指令

    自动选择规则 ffmpeg在处理视频时,如果只提供了输入和输出参数,ffmpeg会自动地去选择相应的视频流和音频流来合成文件 自动选择的方式根据如下规则: 视频流:选分辨率最高的,比如有两个视频,一个 ...

  9. Labview一个循环中放两个事件结构会导致前面板锁定的问题

    建议在同一个循环中,只放置一个事件结构.此时,当一个事件发生时,事件结构将对事件进行处理,然后继续循环,事件结构再等待下一个事件发生. 如在同一个循环中放置两个事件结构,只有在两个事件结构都处理了事件 ...

  10. 关于 RocketMQ 事务消息的正确打开方式 → 你学废了吗

    开心一刻 昨晚和一哥们一起吃夜宵,点了几瓶啤酒 不一会天空下起了小雨,哥们突然道:糟了 我:怎么了 哥们:外面下雨了,我老婆还在等着我去接她 他给了自己一巴掌,说道:真他妈不是个东西 我心想:哥们真是 ...