@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 ...
随机推荐
- jeecms 前台拦截器的研究与改造
jeecms 前台拦截器的研究与改造 2013年12月24日 15:23:35 xinfei0803 阅读数 3511 jeecms出发点是面向大众的,具有前台开发性,也就是说,即时是未登录(游客 ...
- Lamdba表达式的代码使用讲解
public class Lambda{ public static void main(String[] args) { repeat(10, (i)->System.out.print(&q ...
- LA4123 Glenhow Museum
题目大意:蓝书P115 不愧是WF的题 不难发现R的个数为L/2 + 2,O的个数为L/2 - 2 三种做法,第一种比较麻烦,dp[i][j][k][l]表示i个R,j个O,第一个元素是(k)R,最后 ...
- [Array]122. Best Time to Buy and Sell Stock II(obscure)
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- 洛谷1850(NOIp2016) 换教室——期望dp
题目:https://www.luogu.org/problemnew/show/P1850 状态里记录的是”上一回有没有申请“,而不是”上一回申请成功否“,不然“申请 j 次”就没法转移了. dou ...
- mac 将本地文件上传到vps
打开mac终端 假设通过ssh连接远程vps命令为. ssh root@194.10.10.23 -p92322 (说明:92322表示端口号,一般vps端口号默认是22) 那么复制本地文件到终端的命 ...
- 基于jquery鼠标或者移动端滚动加载数据
基于jquery鼠标或者移动端滚动加载数据 var stop = true; // 防止重复请求数据 $(window).scroll(function () { totalheight = pars ...
- Pycharm如何在控制台输出窗口中使用Python解释器
打开菜单栏run->edit configurations,把下图中的复选框选中就可以了.
- Hibernate: insert into xxx (name) values (?)但是数据库中没有数据
学习hibernate 控制台提示 但数据库中没有任何数据被插入 同样的代码,参考例程中就有数据被插入 比较无解,删除部分代码,红框中的部分,运行一下,再贴回去,就好了
- Java中用JXL导出Excel代码详解
jxl是一个韩国人写的java操作excel的工具, 在开源世界中,有两套比较有影响的API可供使用,一个是POI,一个是jExcelAPI.其中功能相对POI比较弱一点.但jExcelAPI对中文支 ...