@codeforces - 715E@ Complete the Permutations
@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的更多相关文章
- Codeforces 715E - Complete the Permutations(第一类斯特林数)
Codeforces 题面传送门 & 洛谷题面传送门 神仙题.在 AC 此题之前,此题已经在我的任务计划中躺了 5 个月的灰了. 首先考虑这个最短距离是什么东西,有点常识的人(大雾)应该知道, ...
- 【CF715E】Complete the Permutations(容斥,第一类斯特林数)
[CF715E]Complete the Permutations(容斥,第一类斯特林数) 题面 CF 洛谷 给定两个排列\(p,q\),但是其中有些位置未知,用\(0\)表示. 现在让你补全两个排列 ...
- CF715E Complete the Permutations(第一类斯特林数)
题目 CF715E Complete the Permutations 做法 先考虑无\(0\)排列的最小花费,其实就是沿着置换交换,花费:\(n-\)环个数,所以我们主要是要求出规定环的个数 考虑连 ...
- codeforces 372 Complete the Word(双指针)
codeforces 372 Complete the Word(双指针) 题链 题意:给出一个字符串,其中'?'代表这个字符是可变的,要求一个连续的26位长的串,其中每个字母都只出现一次 #incl ...
- CF 715 E. Complete the Permutations
CF 715 E. Complete the Permutations 题目大意:给定两个排列\(p,q\)的一部分.定义两个排列\(p,q\)的距离为使用最少的交换次数使得\(p_i=q_i\).对 ...
- 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 ...
- CodeForces 716B Complete the Word
题目链接:http://codeforces.com/problemset/problem/716/B 题目大意: 给出一个字符串,判断其是否存在一个子串(满足:包含26个英文字母且不重复,字串中有‘ ...
- Codeforces Round #337 Alphabet Permutations
E. Alphabet Permutations time limit per test: 1 second memory limit per test: 512 megabytes input: ...
- codeforces 341C Iahub and Permutations(组合数dp)
C. Iahub and Permutations time limit per test 1 second memory limit per test 256 megabytes input sta ...
随机推荐
- PAT甲级——A1042 Shuffling Machine
Shuffling is a procedure used to randomize a deck of playing cards. Because standard shuffling techn ...
- hbase 利用rowkey设计进行多条件查询
摘要 本文主要内容是通过合理Hbase 行键(rowkey)设计实现快速的多条件查询,所采用的方法将所有要用于查询中的列经过一些处理后存储在rowkey中,查询时通过rowkey进行查询,提高rowk ...
- 解决hive无法传参问题思路
由于hive执行过程中参数必须写死,无法进行传递参数.利用shell脚本和java编程进行解决 #!/bin/sh#date = `date -d -1days '+%Y-%m-%d'`if [ $# ...
- Win10操作系统安装—U盘作为启动盘—系统安装到固态硬盘中
利用U盘作为启动盘安装win10操作系统 1.U盘制作为启动盘,制作工具,我选择的是大白菜(个人觉得还是很好用的) 大白菜http://www.bigbaicai.com/rjjc/syjc/3269 ...
- goland快捷键使用
查找替换: 格式化代码块:ctrl+alt+L将选中的行自动对齐:ctrl+alt+I优化没必要的imports:ctrl+alt+O展开代码块:ctrl+“+”展开文件中所有代码块:ctrl+shi ...
- 【转载】传统以太网和时间敏感网络TSN的区别
转载连接:http://www.proav-china.com/News/16800.html ——Biamp亚太区高级工程师 Kane Zhang [专业视听网报道]:[摘要]AVB-Audio ...
- LUOGU P3708 koishi的数学题
传送门 解题思路 发现当x+1时,有的x%i会+1,有的会变成0,而变成0的说明是x的约数,就可以nlogn预处理出每个约数的贡献,然后每次用n-约数. 代码 #include<iostream ...
- android搭建
搭建:https://www.cnblogs.com/zoupeiyang/p/4034517.html#1 android sdk manager 翻墙:http://www.androiddevt ...
- JS高级---学习roadmap---5 parts
JS高级---学习roadmap---5 parts part 1-3 part 4-5
- js 禁止复制粘贴
1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键,其实是禁止快捷菜单,因为不光右键可以弹出这个菜单,键盘上空格 ...