Codeforces 285 E. Positions in Permutations
## [$>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的更多相关文章
- 【CF285E】Positions in Permutations(动态规划,容斥)
		
[CF285E]Positions in Permutations(动态规划,容斥) 题面 CF 洛谷 题解 首先发现恰好很不好算,所以转成至少,这样子只需要确定完一部分数之后剩下随意补. 然后套一个 ...
 - CodeForces - 285E: Positions in Permutations(DP+组合数+容斥)
		
Permutation p is an ordered set of integers p1, p2, ..., pn, consisting of n distinct positive in ...
 - Codeforces 285E - Positions in Permutations(二项式反演+dp)
		
Codeforces 题目传送门 & 洛谷题目传送门 upd on 2021.10.20:修了个 typo( 这是一道 *2600 的 D2E,然鹅为啥我没想到呢?wtcl/dk 首先第一步我 ...
 - CF285 E Positions in Permutations——“恰好->大于”的容斥和允许“随意放”的dp
		
题目:http://codeforces.com/contest/285/problem/E 是2018.7.31的一场考试的题,当时没做出来. 题解:http://www.cnblogs.com/y ...
 - 【codeforces 501D】Misha and Permutations Summation
		
[题目链接]:http://codeforces.com/problemset/problem/501/D [题意] 给你两个排列; 求出它们的字典序num1和num2; 然后让你求出第(num1+n ...
 - 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 ...
 - Codeforces 888D: Almost Identity Permutations(错排公式,组合数)
		
A permutation \(p\) of size \(n\) is an array such that every integer from \(1\) to \(n\) occurs exa ...
 - codeforces 285 D. Permutation Sum  状压  dfs打表
		
题意: 如果有2个排列a,b,定义序列c为: c[i] = (a[i] + b[i] - 2) % n + 1 但是,明显c不一定是一个排列 现在,给出排列的长度n (1 <= n <= ...
 - CF285E Positions in Permutations(dp+容斥)
		
题意,给定n,k,求有多少排列是的 | p[i]-i |=1 的数量为k. Solution 直接dp会有很大的后效性. 所以我们考虑固定k个数字使得它们是合法的,所以我们设dp[i][j][0/1] ...
 
随机推荐
- 【BZOJ】1833 [ZJOI2010]count 数字计数
			
[算法]数位DP [题解] 记忆化搜索 #include<cstdio> #include<algorithm> #include<cstring> #define ...
 - 【BZOJ】3502 PA2012 Tanie linie
			
[算法]贪心,一般DP [题解] --- 胡策k≤10的环状DP做法: 1.钦定法:先确定第一位(可能和第n位)的状态,然后后面正常做DP,显然正确答案是一定会被记录的,因为从整体上看不会有影响. 2 ...
 - Deep learning with Theano 官方中文教程(翻译)(三)——多层感知机(MLP)
			
关于更多的http://deeplearning.net/tutorial/的翻译还有学习笔记会陆续整理传到博客. 供大家相互交流和学习,本人水平有限,若有各种大小错误,还请巨牛大牛小牛微牛们立马拍砖 ...
 - 多重部分和问题    (dp)
			
题目描述 有n种不同大小的数字Ai,每种各Mi个.判断是否能从这些数字中选出若干个使它们的和恰好为K. 这个问题可以用DP求解,递推关系式的定义会影响最终的复杂度. 第一种定义: dp[i+1][j] ...
 - poj 2762 tarjan缩点+拓扑序
			
2013-09-08 10:00 var m, n :longint; t :longint; f, last :..] of longint; pre, other :..] of longint; ...
 - Python作业模拟登陆(第一周)
			
模拟登陆:1. 用户输入帐号密码进行登陆2. 用户信息保存在文件内3. 用户密码输入错误三次后锁定用户 思路: 1. 用户名密码文件为passwd,锁定用户文件为lock 2. 用户输入账号密码采用i ...
 - JSOI2018简要题解
			
来自FallDream的博客,未经允许,请勿转载,谢谢. 有幸拜读到贵省的题目,题的质量还不错,而且相比zjoi可做多了,简单发一下题解吧. 还有就是,怎么markdown在博客园上的代码这么丑啊 「 ...
 - 第三周main参数传递-1 课堂测试
			
课堂测试 main参数传递-1 测试 参考 http://www.cnblogs.com/rocedu/p/6766748.html#SECCLA 在Linux下完成"求命令行传入整数参数的 ...
 - perl HTML::HeadParser获取html头部信息
			
use LWP::Simple; use HTML::HeadParser; use utf8; binmode(STDOUT, ":encoding(gbk)"); #设置win ...
 - linux pthread【转】
			
转自:http://www.cnblogs.com/alanhu/articles/4748943.html Posix线程编程指南(1) 内容: 一. 线程创建 二.线程取消 关于作者 线程创 ...