@description@

给定两个排列 p, q,他们中的有些位置被替换成了 0。

两个排列 p, q 的距离为:最少需要在 p 中执行交换两个元素的操作,使得 p, q 相等。

对于每个 0 <= k <= n,求有多少将 0 替换回正整数并满足 p, q 依然是排列的替换方法,使得 p, q 距离为 k。

原题戳这里

@solution@

考虑两个排列的距离怎么算。如果把 p[i] -> q[i] 看成一个置换,就是将置换排序最少需要的交换次数。

这是个经典问题,答案为 (n - 该置换含有的循环数量)。

考虑一种特殊情况:如果给定完整的 p 而 q 全零,实际上就是求 n 个数划分成 n-k 个循环的方案数,即第一类斯特林数。

因此本题跟第一类斯特林数或多或少有些勾连。

通过 p, q 中已经给定的数,可以把现在已有的循环求出来。剩余的一定会形成若干条链。

直接拿现有的链去作第一类斯特林数?貌似不行。考虑一个例子:p = {1, 0}, q = {0, 2},此时 1 与 2 不可能在同一循环。

形象化地描述,假如 p[i] = a 且 q[i] = 0,可以理解为 a 的下面凸,否则认为 a 的下面凹;同理,假如有 p[j] = 0 且 q[j] = b,可以理解为 b 的上面凸,否则认为 b 的上面凹。

则如果可以 a->b 应该满足 a 的下面与 b 的上面应该为一凹一凸。

一个链中间的东西对链的转移没有限制,只有两个端点会产生限制。

假如一个链形如 a -> ... -> b,则这条链上面的凹凸性取决 a,下面的凹凸性取决 b。

因此一条链的限制可以描述为上下的凹凸性,我们可以将所有链分为 4 类。

为了避免出现更多的分类讨论,我们假设 p[i] = 0, q[i] = 0 的 i 为上下都凸的链(理解成 p[i] = n + i, q[i] = 0 与 p[n + i] = 0, q[n + i] = n + i 也行)。

那么问题转成了给定 4 类链的数量,求将这些链划分为 p 个循环的方案数。

回到我们一开始的想法:这种题与第一类斯特林数有点关系。因此类比第一类斯特林数的递推式子进行 dp。

斯特林数的递推式子:每次加入一个数,要么单独成一个循环,要么接在前面已经加入的某个数的后面。

先把不是上下都凹的全部求第一类斯特林数。但可能会出现不合法情况:凸凸相接或凹凹相接。

凸凸相接直接把上下都凹的当作润滑剂塞进去,凹凹相接没办法,只能在 dp 中限制。

所以 dp 时不让上凹下凸的接在上凸下凹的后面即可。其他和斯特林数一样。

时间复杂度貌似是 O(n^2)?

@accepted code@

#include <cstdio>
const int MAXN = 250;
const int MOD = 998244353;
int f[MAXN + 5], g[MAXN + 5], c[4];
void solve() {
int p = 0; f[0] = 1;
for(int i=1;i<=c[0];i++) f[0] = 1LL*f[0]*i%MOD;
for(int i=1;i<=c[3];i++) {
for(int j=0;j<=p;j++) g[j] = f[j], f[j] = 0;
p++;
for(int j=1;j<=p;j++) f[j] = (1LL*g[j]*(i-1)%MOD + g[j-1]) % MOD;
}
for(int i=1;i<=c[2];i++) {
for(int j=0;j<=p;j++) g[j] = f[j], f[j] = 0;
p++;
for(int j=1;j<=p;j++) f[j] = (1LL*g[j]*(c[3]+i-1)%MOD + g[j-1]) % MOD;
}
for(int i=1;i<=c[1];i++) {
for(int j=0;j<=p;j++) g[j] = f[j], f[j] = 0;
p++;
for(int j=1;j<=p;j++) f[j] = (1LL*g[j]*(c[3]+i-1)%MOD + g[j-1]) % MOD;
}
}
int a[MAXN + 5], b[MAXN + 5], n;
int u[MAXN + 5], d[MAXN + 5], p[MAXN + 5];
bool vis[MAXN + 5];
int main() {
scanf("%d", &n);
for(int i=1;i<=n;i++) scanf("%d", &a[i]), u[a[i]] = i;
for(int i=1;i<=n;i++) scanf("%d", &b[i]), d[b[i]] = i;
for(int i=1;i<=n;i++)
if( u[i] ) p[i] = b[u[i]];
for(int i=1;i<=n;i++)
if( !d[i] || !a[d[i]] ) {
int x = i;
while( p[x] )
vis[x] = true, x = p[x];
vis[x] = true;
if( !d[i] ) {
if( !u[x] ) c[0]++;
else c[1]++;
}
else {
if( !u[x] ) c[2]++;
else c[3]++;
}
}
int cnt = 0;
for(int i=1;i<=n;i++) {
if( vis[i] ) continue;
int x = i;
do {
vis[x] = true;
x = p[x];
}while( x != i );
cnt++;
}
for(int i=1;i<=n;i++)
if( !a[i] && !b[i] ) c[3]++;
solve();
for(int i=n;i>=cnt&&i>=1;i--)
printf("%d ", f[i-cnt]);
for(int i=cnt-1;i>=1;i--) printf("%d ", 0);
}

@details@

这种题难度值3400?貌似官方给的是 fft 做法?

话说我也不知道我是怎么想到这么“形象”的理解的。

感觉“形象”到有点抽象了。

@codeforces - 715E@ Complete the Permutations的更多相关文章

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

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

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

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

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

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

  4. codeforces 372 Complete the Word(双指针)

    codeforces 372 Complete the Word(双指针) 题链 题意:给出一个字符串,其中'?'代表这个字符是可变的,要求一个连续的26位长的串,其中每个字母都只出现一次 #incl ...

  5. CF 715 E. Complete the Permutations

    CF 715 E. Complete the Permutations 题目大意:给定两个排列\(p,q\)的一部分.定义两个排列\(p,q\)的距离为使用最少的交换次数使得\(p_i=q_i\).对 ...

  6. Codeforces 716B Complete the Word【模拟】 (Codeforces Round #372 (Div. 2))

    B. Complete the Word time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  7. CodeForces 716B Complete the Word

    题目链接:http://codeforces.com/problemset/problem/716/B 题目大意: 给出一个字符串,判断其是否存在一个子串(满足:包含26个英文字母且不重复,字串中有‘ ...

  8. Codeforces Round #337 Alphabet Permutations

    E. Alphabet Permutations time limit per test:  1 second memory limit per test:  512 megabytes input: ...

  9. codeforces 341C Iahub and Permutations(组合数dp)

    C. Iahub and Permutations time limit per test 1 second memory limit per test 256 megabytes input sta ...

随机推荐

  1. centos7 盘符变动 绑定槽位

    服务器下的硬盘主有机械硬盘.固态硬盘以及raid阵列,通常内核分配盘符的顺序是/dev/sda./dev/sdb… ….在系统启动过程中,内核会按照扫描到硬盘的顺序分配盘符(先分配直通的,再分配阵列) ...

  2. JSP四大域对象与九大内置对象

    什么是内置对象? 在jsp开发中会频繁使用到一些对象,如 ServletContext.HttpSession.PageContext 等: 如果每次我们在jsp页面中需要使用这些对象都要自己亲自动手 ...

  3. 在windows系统和linux系统中查询IP地址命令的不同

    在linux和windows系统上查询IP地址的命令是不一样的.         在linux中的命令行模式下,输入ifconfig即可查询到IP.而在windows系统下要查询IP地址需要先打开do ...

  4. 斐波那契字符串_KMP

    前言:通过这道题恶补了一下字符串匹配的知识 思路:首先就是求出菲波那切字符串,这个很简单,但是要注意递归超时的问题,可以考虑加上备忘录,或者用递推法,接下来就是匹配问题了,常规的BF会超时,所以要用K ...

  5. idea中隐藏.idea文件夹和.iml文件

    idea中的.idea文件夹和.iml是平常几乎不使用的文件,在创建父子工程或者聚合工程时反而会对我们操作产生干扰,所以,一般情况下,我们都将其隐藏掉,步骤如下: 操作前: 具体操作:File——&g ...

  6. 【JZOJ5231】【NOIP2017模拟A组模拟8.5】序列问题 线段树

    题面 100 在\(O(n^2)\)的基础上,我们可以用线段树来加速. 枚举了左端点之后,需要知道以这个左端点为起点的前缀max,前缀min. 这里只讨论前缀max,前缀min同理. 当我们倒序枚举左 ...

  7. [jnhs]netbeans使用debug模式频繁出现java.lang.OutOfMemoryError: PermGen space内存不足

    netbeans赠送的tomcat7 windows解决方法: 修改C:\Program Files\Apache Software Foundation\Apache Tomcat 8.0.27\b ...

  8. 常用命令4-文件搜索命令 2- which

    大家发现,cd 使用whereis和使用which都找不到他所在位置.是因为cd是linux的shell内置命令.那什么是shell,就是当前咱们操作界面.咱们看到的ls等命令都是通过外部安装的,所以 ...

  9. ssh连接超时中断问题解决方案

    当在终端使用ssh命令连接到服务器时,如果一段时间没有活动连接会被中断,以下有两种方案可以解决: 一.修改ssh客户端配置 编辑客户端 /etc/ssh/ssh_config (或~/.ssh/con ...

  10. input输入框校验

    1.只能输入数字,当输入不符字符删除,光标位置不变 //只能输入数字 function onlyNumTrue(obj){ var reg = /[^\d]/g; var pos = obj.sele ...