CF285E - Positions in Permutations 分析
题目概述
对于一个
分析
一看到这道题目,就感觉跟[AGC005D] ~K Perm Counting一样。
考虑容斥,设
那么根据二项式反演可以得到:
考虑怎么求
直接沿用那道题目的分成两部图的方法,然后进行连边,具体而言是左边的
然后我们会依照连边拉出来两条边的数量为
发现这两条链可以分别处理并且都是互不影响的,所以我们先关注一条链。
我们不能选择两条相邻的边,因为这样会导致他不知道在那个位置,这也就转化成了拥有
我们考虑我们选择的序列为
发现这个约束不好做,转化成相差为一的,套路地令
这相当于在
综上所述,拥有
我们现在要将两条链组合起来,设
那么显然有:
那么有:
然后反演求出
代码
时间复杂度
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define int long long
#define N 1005
using namespace std;
const int mod = 1e9 + 7;
int jc[N],inv[N];
int C(int a,int b) {
if (a < 0 || b < 0 || a < b) return 0;
return jc[a] * inv[b] % mod * inv[a - b] % mod;
}
int f[N];
signed main(){
jc[0] = jc[1] = inv[0] = inv[1] = 1;
for (int i = 2;i < N;i ++) jc[i] = jc[i - 1] * i % mod,inv[i] = (mod - mod / i) * inv[mod % i] % mod;
for (int i = 2;i < N;i ++) inv[i] = inv[i - 1] * inv[i] % mod;
int n,k;
cin >> n >> k;
for (int i = 0;i <= n;i ++)
for (int j = 0;j <= i;j ++) f[i] = (f[i] + C(n - j,j) * C(n - (i - j),i - j) % mod) % mod;
int ans = 0;
for (int i = k,t = 1;i <= n;i ++,t = -t)
ans = (ans + (t * C(i,k) % mod * f[i] % mod * jc[n - i] % mod + mod) % mod) % mod;
cout << ans;
return 0;
}