@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 ...
随机推荐
- 【Redis安装】部署与基本配置 --基于Mac和Linux
Redis安装与部署[基于Mac和Linux] 一.Redis简介 基于内存的Key-Value高性能NoSQL数据库 二.Redis下载和解压 进入官网下载最新版的Redis,目前是5.0.0,这个 ...
- PAT甲级——A1043 Is It a Binary Search Tree
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following propertie ...
- GUID 使用方法
GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的.通常平台会提供生成GUID的API.生成算法很有意思,用到了以太网卡地址.纳秒级时间.芯片ID码和许多可 ...
- Alpha通道是什么意思,和rgb通道有什么区别
Alpha通道是什么意思,和rgb通道有什么区别 Alpha通道: 阿尔法通道是一个8位的灰度通道,该通道用256级灰度来记录图像中的透明度信息,定义透明.不透明和半透明区域,其中白表示不透明,黑表示 ...
- VS2013生成、使用dll,lib文件
VS2013生成DLL文件 vs2013创建及使用DLL 一般来说项目偏爱生成dll动态库文件,因为可以解决静态库造成的空间浪费和更新困难问题,另外创建静态库时,我一般是建立空项目后,在项目配置类型中 ...
- 【python之路24】装饰器
1.装饰器的应用场景 通常IT公司的程序开发是分工的,例如某公司某个部门负责底层函数的开发,另一个部门利用其函数实现高级功能,那么如果负责底层开发的函数需要改动,一般来说不会直接在函数上进行修改,通常 ...
- hdu 5823 color II——子集dp(独立集)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5823 独立集染一种颜色.在这个基础上枚举子集来dp. 状压一样地存边真是美妙. 2^32是1ll<& ...
- TZ_03_mybatis的注解开发
1.一对多的注解开发 1>需求通过查询所有的用户,并且找到该用户的所有账户(使用延迟加载模式) @Select("select * from user") //sql语句查询 ...
- js的Date()时间对象
var nowDate = new Date(); nowDate.getYear(); //获取当前年份(2位) nowDate.getFullYear(); //获取完整的年份(4位,1970-? ...
- Lvs 环境搭建 vbox搭建centos6.9 vbox设置 centos上安装nginx
1.现在vbox上虚拟出3个虚拟机,分别为负载均衡器(Load Balance).实际服务器1(Real server1).实际服务器2(Real Server2) 要点: :vbox系统网络连接方式 ...