@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. 1.关于Spring Cloud的一些基本知识

    GA代表 general avaliable 通用可用版  也就是 正式发行版 PRE 代表预版本  就是还没有成熟 SNAPSHOT 快照版 这个版本可用 没有bug但是后期还会改进 选了这个spr ...

  2. c++ 链接mysql:error LNK2019: 无法解析的外部符号

    使用VS2012编译项目报错如下: error LNK2019: 无法解析的外部符号 _mysql_real_connect@32,该符号在函数 _main 中被引用 error LNK2019: 无 ...

  3. python 搜索匹配文件目录下所有的jpg或者png图片

    import glob PATH_TO_TEST_IMAGES_DIR = 'D:\TrainChangeFifteenData\Picture\Test' for pidImage in glob. ...

  4. git 远程服务器创建项目自动化部署、克隆推送免密码

    1.用git用户 在git目录下 创建裸仓库 git init --bare project_01.git 2.在裸仓库的 hooks目录下创建 post-receive 文件775 3.post-r ...

  5. 2018-2-13-解决-vs-出现Error-MC3000-给定编码中的字符无效

    title author date CreateTime categories 解决 vs 出现Error MC3000 给定编码中的字符无效 lindexi 2018-2-13 17:23:3 +0 ...

  6. Hadoop 集群硬件配置

  7. Python eval()函数的用法

    Python eval()函数的用法 eval(str)函数很强大,官方解释为:将字符串str当成有效的表达式来求值并返回计算结果.所以,结合math当成一个计算器很好用. eval()函数常见作用有 ...

  8. vim编辑器操作①

    Linux文本编辑器: 行编辑器:sed 全屏编辑器:nano,vi/vim 本文主要介绍说明vim编辑器的相关使用: 其有三种模式,即: 编辑模式(默认模式).插入模式(输入模式).末行模式(内置的 ...

  9. IDEA javax.servlet.http.HttpServletRequest; 不存在 解决方案

    使用idea创建一个web项目,在项目中报HttpServletRequest和HttpServletResponse不存在. 问题原因:idea不会默认引用tomcat的jar包. 解决方法: [注 ...

  10. 【python之路41】web框架

    一.web框架介绍 一共有两种web框架 1.既包含socket又能逻辑处理 tornado框架 2.只能处理逻辑 Django bottle flask  二.web框架的本质 众所周知,对于所有的 ...