## [$>Codeforces \space 285 E. Positions in Permutations

题目大意 : 定义一个长度为 \(n\) 的排列中第 \(i\) 个元素是好的,当且仅当 \(i\)在排列中的位置 \(p_i\) 满足 \(|i - p_i| = 1\), 给出 \(n, k\) 求长度为 \(n\) 的排列中恰好有 \(k\) 个元素是好的方案数

$1 \leq n \leq 1000, 0 \leq k \leq n $

解题思路 :

观察发现,直接求出答案貌似十分困难,不妨先 \(dp\) 出至少 \(k\) 个元素是好的方案数,然后再通过 容斥/反演 来解决

至少有 \(k\) 个元素是好的方案数等价于有 \(k\) 个位置存在匹配 \(|i-p_i| = 1\) ,剩余元素随便排列的方案数

设 \(f[i][j][0/1][0/1]\) 表示前 \(i\) 个元素和前 \(i\) 个位置产生了 \(j\) 对匹配,第 \(i\) 个元素和第 \(i\) 个位置是否已经被匹配的方案数

转移很显然,只需要枚举 \(i-1\) 上的元素和位置是否能和 \(i\) 上的元素和位置产生匹配即可

设 \(F(k)\) 表示至少有 \(k\) 个是好的方案数,那么 \(k = f[n][k] \times(n-k)!\)

考虑要求 \(Ans_k =\) 恰好有 \(k\) 个元素是好的方案数,那么有 \(Ans_k = \sum_{i = k}^{n} (-1)^{i-k} \times C_i^k \times F(i)\)

这个和最基础的容斥又有所不一样,简单的考虑,对于 \(i > k\) 的每一个 \(Ans_i\) ,其中任意选 \(k\) 个好元素都能更新到 \(Ans_k\) ,所以方案数是 \(C_i^k\) ,在容斥进行补集转换的时候需要乘上这个系数

往复杂了讲,这个涉及到容斥原理最本质的在集合上的运算,之前的 \(i\) 将表示所有大小为 \(i\) 的集合,那么每一个大小为 \(i\) 的集合在算到 \(Ans_k\) 的过程中都产生了 \(C_i^k\) 个不同的大小为 \(k\) 的集合

当中的具体证明可以看近年集训队论文,或者我的好友 cly_none的博客

考虑到前面算 \(F(i)\) 的时候,两个不同的匹配方案可能会对应到同一个排列,这里等价于每一个大小为 \(i\) 的集合,选 \(k\) 个好元素得到的新集合可能相同,所以两个重复计数恰好抵消了

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define N (2005)
#define int ll
const int Mod = 1000000007;
int js[N], inv[N], f[N][N][2][2], g[N], n, k;
inline int pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = a * a % Mod)
if(b & 1) ans = ans * a % Mod;
return ans;
}
inline int C(int n, int i){ return js[n] * inv[i] % Mod * inv[n-i] % Mod; }
main(){
read(n), read(k), f[0][0][0][0] = 1, js[0] = inv[0] = 1;
for(int i = 1; i <= n; i++){
js[i] = js[i-1] * i % Mod;
inv[i] = pow(js[i], Mod - 2);
}
for(int i = 1; i <= n; i++)
for(int j = 0; j <= n; j++){
(f[i][j][0][0] += f[i-1][j][0][0] + f[i-1][j][1][1]) %= Mod;
(f[i][j][0][0] += f[i-1][j][0][1] + f[i-1][j][1][0]) %= Mod;
if(j >= 1 && i > 1){
(f[i][j][1][0] += f[i-1][j-1][1][0] + f[i-1][j-1][0][0]) %= Mod;
(f[i][j][0][1] += f[i-1][j-1][0][1] + f[i-1][j-1][0][0]) %= Mod;
}
if(j >= 2 && i > 1) (f[i][j][1][1] += f[i-1][j-2][0][0]) %= Mod;
}
for(int i = 0; i <= n; i++){
int res = 0;
(res += f[n][i][0][0] + f[n][i][1][0]) %= Mod;
(res += f[n][i][0][1] + f[n][i][1][1]) %= Mod;
g[i] = res * js[n-i] % Mod;
}
int ans = 0;
for(int i = k; i <= n; i++){
int p = ((i - k) & 1) ? Mod - 1 : 1;
(ans += C(i, k) * p % Mod * g[i] % Mod) %= Mod;
}
cout << ans << endl;
return 0;
}

Codeforces 285 E. Positions in Permutations的更多相关文章

  1. 【CF285E】Positions in Permutations(动态规划,容斥)

    [CF285E]Positions in Permutations(动态规划,容斥) 题面 CF 洛谷 题解 首先发现恰好很不好算,所以转成至少,这样子只需要确定完一部分数之后剩下随意补. 然后套一个 ...

  2. CodeForces - 285E: Positions in Permutations(DP+组合数+容斥)

    Permutation p is an ordered set of integers p1,  p2,  ...,  pn, consisting of n distinct positive in ...

  3. Codeforces 285E - Positions in Permutations(二项式反演+dp)

    Codeforces 题目传送门 & 洛谷题目传送门 upd on 2021.10.20:修了个 typo( 这是一道 *2600 的 D2E,然鹅为啥我没想到呢?wtcl/dk 首先第一步我 ...

  4. CF285 E Positions in Permutations——“恰好->大于”的容斥和允许“随意放”的dp

    题目:http://codeforces.com/contest/285/problem/E 是2018.7.31的一场考试的题,当时没做出来. 题解:http://www.cnblogs.com/y ...

  5. 【codeforces 501D】Misha and Permutations Summation

    [题目链接]:http://codeforces.com/problemset/problem/501/D [题意] 给你两个排列; 求出它们的字典序num1和num2; 然后让你求出第(num1+n ...

  6. Educational Codeforces Round 32 Almost Identity Permutations CodeForces - 888D (组合数学)

    A permutation p of size n is an array such that every integer from 1 to n occurs exactly once in thi ...

  7. Codeforces 888D: Almost Identity Permutations(错排公式,组合数)

    A permutation \(p\) of size \(n\) is an array such that every integer from \(1\) to \(n\) occurs exa ...

  8. codeforces 285 D. Permutation Sum 状压 dfs打表

    题意: 如果有2个排列a,b,定义序列c为: c[i] = (a[i] + b[i] - 2) % n + 1 但是,明显c不一定是一个排列 现在,给出排列的长度n (1 <= n <= ...

  9. CF285E Positions in Permutations(dp+容斥)

    题意,给定n,k,求有多少排列是的 | p[i]-i |=1 的数量为k. Solution 直接dp会有很大的后效性. 所以我们考虑固定k个数字使得它们是合法的,所以我们设dp[i][j][0/1] ...

随机推荐

  1. 【BZOJ1272】Gate Of Babylon [Lucas][组合数][逆元]

    Gate Of Babylon Time Limit: 10 Sec  Memory Limit: 162 MB[Submit][Status][Discuss] Description Input ...

  2. 「6月雅礼集训 2017 Day11」tree

    [题目大意] 给出一棵带权树,有两类点,一类黑点,一类白点. 求切断黑点和白点间路径的最小代价. $n \leq 10^5$ [题解] 直接最小割能过..但是树形dp明显更好写 设$f_{x,0/1/ ...

  3. gdoi2017

    今年的gdoi第一天t1大水题一道 裸的kmp 但是 我把记录长度的int数组开成了char类型 正解变爆零 心态爆炸......... 后面的第二题两千字题目以及五千字附加故事(我是没有去看,据说全 ...

  4. HDU 1070 Milk (模拟)

    题目链接 Problem Description Ignatius drinks milk everyday, now he is in the supermarket and he wants to ...

  5. 寻找kernel32.dll的地址

    为了寻找kernel32.dll的地址,可以直接输出,也可以通过TEB,PEB等查找. 寻找TEB: dt _TEB nt!_TEB +0x000 NtTib : _NT_TIB +0x01c Env ...

  6. go环境变量及build文件

    package main /* windows go环境设置: # 参考:https://blog.csdn.net/quicmous/article/details/80360126 GOROOT ...

  7. kernel cmdline

    從 lk 傳送到 kerel 的 cmdline 會放在開機後的 adb /proc/cmdline 開到 android 後,又會被讀出來 /system/core/init/util.cpp 27 ...

  8. python基础===8道基础知识题

    本文转自微信公众号: 2018-03-12 leoxin 菜鸟学Python 原文地址:http://mp.weixin.qq.com/s/JJSDv5YJOZ9e3hn28zWIsQ NO.1 Py ...

  9. sicily 数据结构 1014. Translation

    Description You have just moved from Waterloo to a big city. The people here speak an incomprehensib ...

  10. java.lang.ClassCastException: org.springframework.web.filter.CharacterEncodingFilter cannot be cast

    严重: Exception starting filter encodingFilterjava.lang.ClassCastException: org.springframework.web.fi ...