CF 715 E. Complete the Permutations

题目大意:给定两个排列\(p,q\)的一部分。定义两个排列\(p,q\)的距离为使用最少的交换次数使得\(p_i=q_i\)。对于所有\(0\leq k\leq n-1\)的所有补全方案中距离为\(k\)的方案数。

\(\\\)

将排列看成置换的话,两个完整的排列的距离为\(n-m\),其中\(m\)为循环节个数。

现在考虑将所有存在的不完整的循环节找出来。先连边:对于每个\(i\),连\(a_i\to b_i\),然后若\(a_i=b_j\neq 0,\)则连\(b_j\to a_i\)。显然对于每个\(i\),\(a_i,b_i\)只有四种情况:

  1. \(0\to x\)
  2. \(x\to 0\)
  3. \(0\to 0\)
  4. \(x\to y\)

如果出现了第\(4\)种边,那么我们这两个点缩成一个无实际意义的点。对于\(a_i=b_j\neq 0\)的情况,我们也进行同样的处理。这样就只剩上面的\(3\)种链了。然后再将这些链组成环。

首先有个性质,如果\(x\)存在,那么它只会存在于\(1\)或\(2\)中的一种链,所以对于\(1\)类链,其中的\(x\)只会向外连向一个\(0\);对第二类链同理。所以如果一个环中同时存在在\(1,2\)类链,那么必定存在\(3\)类链在中间连接。

还发现,一个环可以是纯粹由\(1\)类或者\(2\)类链组成。

于是我们考虑对\(1,2\)类链分别处理。

以\(1\)类为例。设这\(3\)种链的数量分别为\(a,b,c\)。设\(f_i\)为组成了至少\(i\)个纯种\(1\)类环的方案数,则:

\[f_i=\sum_{j=i}^a\binom{a}{j}\begin{bmatrix}j\\i\end{bmatrix}(a-j+c)^{\underline{a-j}}
\]

首先\(\binom{a}{j}\)选出\(j\)条链,然后第一类斯特林数\(\begin{bmatrix}j\\i\end{bmatrix}\)将其组成\(i\)个环排列。最后的\((a-j+c)^{\underline{a-j}}\)表示剩下的\(a-j\)个\(1\)类链还要连出去一条边。之前说了,\(1\)类链的\(x\)只能连向\(0\),所以可以选择的对象有为不在环上的\(1\)类链和\(3\)类链(\(a-j+c\)个),又因为每个链最多只有一个入边,所以是\((a-j+c)^{\underline{a-j}}\)。但是有可能在这个过程中产生新的环,于是容斥一下就好了。

设\(g\)为\(2\)类链的答案。我们将\(q=f*g\)。\(q_i\)就是纯种\(1,2\)类链一共有\(i\)个的方案数。其他的没有在环上的\(1,2\)类链,它们与\(3\)类链组合在了一起。有一下几种“原件":

  1. \((0\to x)_n\to 0\to 0\to(x\to0)_m\)
  2. \((0\to x)_n\to 0\to 0\)
  3. \(0\to 0\to (x\to 0)_m\)
  4. \(0\to 0\)

我们发现每种原件中有且仅有一个\(0\to 0\),所以这些原件组成\(i\)个环的方案数就是\(\begin{bmatrix}c\\i \end{bmatrix}\)。所以,设\(s_i=\begin{bmatrix}c\\i \end{bmatrix}\)。则还要将\(q\)卷上\(s\)。

最终,有\(i\)个环的排列个数就是\((q*s)_i\times c!\)。

对于一个环,我们可以写成\(a_{p_1}\to b_{p_1}\to a_{p_2}\to b_{p_2}...\to a_{p_n}\to b_{p_{n}}\to a_{p_1}\)(\(a_i\)为上方的排列,\(b_i\)为下方的排列)。对于每个\(b_{p_i}=a_{p_{i+1}}=0\)的位置,我们要给\(b_{p_i}\)一个标号,当\(b_{p_i}\)确定了,\(a_{p_{i+1}}\)的值也就确定了(但不一定等于\(b_{p_i}\))。这样的\(b_{p_i}\)一定有\(c\)个,所以乘上\(c!\)。

下面解释为什么\(a_{p_{i+1}}\)不一定等于\(b_{p_i}\)。之前对于所有的\(x\to y\),我们直接忽略了这个边(假设这个边是\(a_j\to b_j\)),假设现在我令\(b_{p_i}=x\),那么我们应该讲\(a_j\to b_j\)插入\(b_{p_i}\to a_{p_{i+1}}\)中,即:\(b_{p_i}\to a_j \to b_j \to a_{p_{i+1}}\),显然\(a_{p_{i+1}}=b_j\)了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 2005 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} const ll mod=998244353;
ll ksm(ll t,ll x) {
ll ans=1;
for(;x;x>>=1,t=t*t%mod)
if(x&1) ans=ans*t%mod;
return ans;
}
int n;
int a[N],b[N];
ll S[N][N],C[N][N];
ll fac[N],ifac[N];
int cnt[3];
int opp[N],exi[N],exb[N];
int tag[N];
int cir;
ll f[N],g[N]; void dfs(int v,int f) {
tag[v]=1;
if(!b[v]) {
if(!f) {
cnt[2]++;
} else cnt[1]++;
return ;
}
if(exi[b[v]]) {
if(tag[exi[b[v]]]) cir++;
else dfs(exi[b[v]],f);
} else if(!f) cnt[0]++;
}
ll h[N];
ll ans[N];
int main() {
n=Get();
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
ifac[n]=ksm(fac[n],mod-2);
for(int i=n-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
for(int i=0;i<=n;i++)
for(int j=0;j<=i;j++)
C[i][j]=(!j||i==j)?1:(C[i-1][j-1]+C[i-1][j])%mod;
S[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
S[i][j]=(S[i-1][j-1]+S[i-1][j]*(i-1))%mod;
for(int i=1;i<=n;i++) a[i]=Get();
for(int i=1;i<=n;i++) b[i]=Get();
for(int i=1;i<=n;i++) if(a[i]) exi[a[i]]=i;
for(int i=1;i<=n;i++) if(b[i]) exb[b[i]]=i;
for(int i=1;i<=n;i++) {
if(a[i]&&exb[a[i]]) continue ;
dfs(i,a[i]);
}
for(int i=1;i<=n;i++) if(!tag[i]) dfs(i,a[i]); for(int i=0;i<=cnt[0];i++)
for(int j=i;j<=cnt[0];j++)
(f[i]+=C[cnt[0]][j]*S[j][i]%mod*fac[cnt[0]-j+cnt[2]]%mod*ifac[cnt[2]])%=mod;
for(int i=cnt[0];i>=0;i--)
for(int j=i+1;j<=cnt[0];j++)
f[i]=(f[i]-C[j][i]*f[j]%mod+mod)%mod; for(int i=0;i<=cnt[1];i++)
for(int j=i;j<=cnt[1];j++)
(g[i]+=C[cnt[1]][j]*S[j][i]%mod*fac[cnt[1]-j+cnt[2]]%mod*ifac[cnt[2]])%=mod; for(int i=cnt[1];i>=0;i--)
for(int j=i+1;j<=cnt[1];j++)
g[i]=(g[i]-C[j][i]*g[j]%mod+mod)%mod;
for(int i=0;i<=n;i++)
for(int j=0;j<=i;j++)
(h[i]+=f[j]*g[i-j])%=mod;
for(int i=0;i<=n;i++)
for(int j=0;j<=i;j++)
(ans[i]+=h[j]*S[cnt[2]][i-j]%mod*fac[cnt[2]])%=mod;
for(int i=n;i>=1;i--)
if(i>=cir) ans[i]=ans[i-cir];
else ans[i]=0;
for(int i=n;i>=1;i--) cout<<ans[i]<<" ";
return 0;
}

CF 715 E. Complete the Permutations的更多相关文章

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

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

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

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

  3. CF 1093 E. Intersection of Permutations

    E. Intersection of Permutations 链接 题意: 给定两个序列,询问第一个排列的[l1,r1]和第二个排列[l2,r2]中有多少个共同的数,支持在第二个排列中交换两个数. ...

  4. cf 251 B Playing with Permutations 暴力 分类讨论

    题链;http://codeforces.com/problemset/problem/251/B B. Playing with Permutations time limit per test 2 ...

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

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

  6. @codeforces - 715E@ Complete the Permutations

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

  7. CF715E—— Complete the Permutations

    传送门:QAQQAQ 题意:给你两个$1$~$n$的排列,0表示该位置数字不确定,两两交换第一个排列中的元素使之变成第二个排列,令$s[x]$表示对于所有不同的两个排列,最少交换次数为$x$的序列有$ ...

  8. Codeforces 715E - Complete the Permutations(第一类斯特林数)

    Codeforces 题面传送门 & 洛谷题面传送门 神仙题.在 AC 此题之前,此题已经在我的任务计划中躺了 5 个月的灰了. 首先考虑这个最短距离是什么东西,有点常识的人(大雾)应该知道, ...

  9. Solution Set - Stirling 数相关杂题

      <好多题的题解>   「洛谷 P5408」第一类斯特林数·行   根据结论 \[x^{\overline{n}}=\sum_i{n\brack i}x^i, \] 我们只需要求出 \( ...

随机推荐

  1. mongodb复杂条件查询 (or与and)

    分类专栏: mongodb   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/tjbsl/ ...

  2. 修复dtcms5.0后台管理编辑器上传视频和图片被过滤问题

    1.原程序代码调用上传接口文件路径更改为父节点相对路径: 2.修复ueditor.config.js配置: img: ['src', 'alt', 'title', 'width', 'height' ...

  3. background 设置文本框背景图

    background 属性的作用是给元素设置背景,它是一个复合属性,常用的子属性如下: background-color 指定元素的背景颜色. background-image 指定元素的背景图像. ...

  4. js 设计模式——策略模式

    策略模式(Strategy) 定义:将定义的一组算法封装起来,使其相互之间可以替换.封装的算法具有一定的独立性,不会随客户端的变化而变化 废话不多说,先来个例子 // 例如要写一个计算两个数加减乘除的 ...

  5. CTF必备技能丨Linux Pwn入门教程——栈溢出基础

    这是一套Linux Pwn入门教程系列,作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的一些题目和文章整理出一份相对完整的Linux Pwn教程. 课程回顾>>Linux ...

  6. 3-8 pivot操作

      数据透视表¶ In [1]: import pandas as pd excelample=pd.DataFrame({'Month':["January","Jan ...

  7. python简单日志处理

    简单日志处理 import datetime import re logfile='''58.61.164.141 - - [22/Feb/2010:09:51:46 +0800] "GET ...

  8. 2016 ACM-ICPC Asia Regional Dalian Online HDU 5875 Function(线段树)

    题意 求区间l~r的a[l]%a[l+1]%--%a[r]的值 思路 因为取模的变化是很快的,所以线段树查找区间内第一个小于等于a[l]的数的位置,更新ans后继续查找即可. 注意查询满足某种条件的位 ...

  9. AWS之EC2搭建WordPress博客

    AWS之搭建WordPress博客 注意:请确定您已经成功完成LAMP架构的搭建; 1.下载并解压WordPress安装包: ①使用wget命令在WordPress官网获取最新安装包: [ec2-us ...

  10. 从写下第1个脚本到年薪30W,我的自动化测试心路历程

    我希望我的故事能够激励现在的软件测试人,尤其是还坚持在做“点点点”的测试人. 你可能会有疑问:“我也能做到这一点的可能性有多大?”因此,我会尽量把自己做决定和思考的过程讲得更具体一些,并尽量体现更多细 ...