题意:求所有长度为\(n\)的排列\(p\)中,有多少个满足:对于所有\(i \,(1 \leq i \leq n)\),其中恰好有\(k\)个满足\(|p_i - i| = 1\)。答案对\(10^9 + 7\)取模。

\(n \leq 10^3\)

首先,让我们考虑这个类似反演的结论:

对于\(F(n)\)和\(f(n)\),则满足

\[F(n) = \sum_{k \geq n}{{k}\choose{n}}f(k) \iff f(n) = \sum_{k \geq n}(-1)^{k-n}{{k}\choose{n}}F(k)
\]

对于充分性,我们有

\[\begin{aligned} & \sum_{k \geq n}(-1)^{k-n}{{k}\choose{n}}F(k) \\
= & \sum_{k \geq n}(-1)^{k-n}{{k}\choose{n}} \sum_{j \geq k} {{j}\choose{k}} f(j) \\
= & \sum_{j \geq n} f(j) {{j}\choose{n}} \sum_{n \leq k \leq j} (-1)^{k-n} {{j-n}\choose{k-n}} \\
= & \sum_{j \geq n} f(j) {{j}\choose{n}} \sum_{0 \leq k \leq j-n} (-1)^k {{j-n}\choose{k}} \\
= & \sum_{j \geq n} f(j) {{j}\choose{n}} (1-1)^{j-n} \\
= & f(n)\end{aligned}
\]

而对于必要性,我们也能给出类似的证明。

观察这个结论,不难发现,我们平时使用的容斥就是这个结论求\(f(0)\)时的特殊情况。而现在我们要求的是\(f(k)\),问题就变成了把所有\(F(n)\)都求出来。

\(F(n)\)的定义正对应了我们求至少有\(k\)个的情况总数时,重复统计所得到的结果。这使得它可以比较容易地求出。

我们考虑权值和位置表示为二分图的形式,那么问题就在于求二分图恰好有\(k\)个匹配的方案数。考虑dp。设dp[i,j,a,b]表示当前匹配到第\(i\)个权值和位置,已经有\(j\)个匹配,并且\(a\)和\(b\)分别表示第\(i\)个位置与权值是否已经与编号更小的权值与位置匹配。通过枚举\(a\)和\(b\),很容易能得到dp的转移。当然,最后的答案还要乘以一个阶乘。

时间复杂度\(O(n^2)\)。

#include <bits/stdc++.h>
using namespace std;
const int N = 1010, MOD = 1000000007;
typedef long long ll;
ll power(ll a,int b) {
ll res = 1;
while (b) {
if (b&1) res = 1ll * res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int n,k;
ll dp[N][N][2][2],jc[N],inv[N],ans;
ll comb(int a,int b) {
if (a < 0 || b < 0 || a < b)
return 0;
return jc[a] * inv[b] % MOD * inv[a-b] % MOD;
}
int main() {
scanf("%d%d",&n,&k);
dp[0][0][1][1] = 1;
for (int i = 1 ; i <= n ; ++ i)
for (int j = 0 ; j <= n ; ++ j) {
(dp[i][j][0][0] = dp[i-1][j][0][0] + dp[i-1][j][1][0] + dp[i-1][j][0][1] + dp[i-1][j][1][1]) %= MOD;
if (j >= 1) {
(dp[i][j][1][0] = dp[i-1][j-1][0][0] + dp[i-1][j-1][1][0]) %= MOD;
(dp[i][j][0][1] = dp[i-1][j-1][0][0] + dp[i-1][j-1][0][1]) %= MOD;
}
if (j >= 2)
dp[i][j][1][1] = dp[i-1][j-2][0][0];
}
jc[0] = 1;
for (int i = 1 ; i <= n ; ++ i)
jc[i] = 1ll * i * jc[i-1] % MOD;
inv[n] = power(jc[n],MOD-2);
for (int i = n-1 ; i >= 0 ; -- i)
inv[i] = 1ll * inv[i+1] * (i+1) % MOD;
for (int j = k, p = 1 ; j <= n ; ++ j, p = -p) {
ll v = 1ll * jc[n-j] * (dp[n][j][0][0] + dp[n][j][1][0] + dp[n][j][0][1] + dp[n][j][1][1]) % MOD;
(ans += p * comb(j,k) * v % MOD) %= MOD;
}
ans = (ans % MOD + MOD) % MOD;
cout << ans << endl;
return 0;
}

小结:这种类似于反演的东西是很多组合问题的通用方法,希望自己能实现灵活的运用。

【做题】CF285E. Positions in Permutations——dp+容斥的更多相关文章

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

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

  2. 【CF715E】Complete the Permutations(容斥,第一类斯特林数)

    [CF715E]Complete the Permutations(容斥,第一类斯特林数) 题面 CF 洛谷 给定两个排列\(p,q\),但是其中有些位置未知,用\(0\)表示. 现在让你补全两个排列 ...

  3. [Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥

    题面 传送门:https://www.luogu.org/problemnew/show/P1450 Solution 这是一道很有意思的在背包里面做容斥的题目. 首先,我们可以很轻松地想到暴力做背包 ...

  4. bzoj 3622 DP + 容斥

    LINK 题意:给出n,k,有a,b两种值,a和b间互相配对,求$a>b$的配对组数-b>a的配对组数恰好等于k的情况有多少种. 思路:粗看会想这是道容斥组合题,但关键在于如何得到每个a[ ...

  5. 【BZOJ 4665】 4665: 小w的喜糖 (DP+容斥)

    4665: 小w的喜糖 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 94  Solved: 53 Description 废话不多说,反正小w要发喜 ...

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

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

  7. CDOJ 1294 天行廖的游戏 dp 容斥

    天行廖的游戏 题目连接: http://acm.uestc.edu.cn/#/problem/show/1294 Description 天行健,君子以自强不息.地势坤,廖爷以厚德载物 一日在喵哈哈村 ...

  8. codeforces 342D Xenia and Dominoes(状压dp+容斥)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud D. Xenia and Dominoes Xenia likes puzzles ...

  9. BZOJ.4559.[JLOI2016]成绩比较(DP/容斥 拉格朗日插值)

    BZOJ 洛谷 为什么已经9点了...我写了多久... 求方案数,考虑DP... \(f[i][j]\)表示到第\(i\)门课,还有\(j\)人会被碾压的方案数. 那么\[f[i][j]=\sum_{ ...

随机推荐

  1. 软工网络15团队作业4——Alpha阶段敏捷冲刺4.0

    软工网络15团队作业4--Alpha阶段敏捷冲刺4.0 1.每天举行站立式会议,提供当天站立式会议照片一张. 2.项目每个成员的昨天进展.存在问题.今天安排. 成员 昨天已完成 今天计划完成 郭炜埕 ...

  2. DataSet 读取xml 报错有非法字符

    private void Bind() { string strLogPath = ConfigurationSettings.AppSettings["LOG_PATH"].To ...

  3. HighCharts学习笔记(一)

    HighChars基本概述 Highcharts是一个纯js写成的插件库,很好的外观表现可以满足任何图标需求. 开始使用chart之前进行配置 全局配置: Highcharts.setOptions( ...

  4. https://scrapingclub.com/exercise/detail_cookie/

    def parse(self, response): pattern=re.compile('token=(.*?);') token=pattern.findall( response.header ...

  5. vim 命令学习(基础篇)

    [1]三种模式 vi的三种模式:命令模式.末行模式.编辑模式. 三种模式相互切换逻辑与命令图: 1.命令模式是vi的默认模式(即每打开一个文件时的初始模式). 2.命令模式切换至末行模式,末行模式切换 ...

  6. Spring源码阅读(六)

    这一讲分析spring bean属性注入代码populateBean,源码分析如下 /** * Populate the bean instance in the given BeanWrapper ...

  7. numpy数学数据处理

    数学和统计方法 sum 对数组中全部或某轴向的元素求和.零长度的数组的sum为0. mean 算术平均数.零长度的数组的mean为NaN. import numpy as np import nump ...

  8. centos 6.8 配置csh的shell和环境变量

    1.查看shell 查看系统中安装的所有版本的shell:cat   /etc/shells 查看当前用户使用的shell:echo $SHELL 2.修改用户shell 可以在/etc/passwd ...

  9. AtCoder Beginner Contest 087 (ABC)

    A - Buying Sweets 题目链接:https://abc087.contest.atcoder.jp/tasks/abc087_a Time limit : 2sec / Memory l ...

  10. 大数据学习路线之linux系统基础搭建

    学习大数据是必须掌握一定Linux知识的,工欲善其事,必先利其器.在学习之前,首先需要搭建Linux系统,本节将讲解VMware Workstation的安装和CentOS 7系统的安装. 1.2.1 ...