1. 程式人生 > >[Codeforces 285E]Positions in Permutations(容斥+DP)

[Codeforces 285E]Positions in Permutations(容斥+DP)

Address

Meaning

稱一個 1n1\sim n 的排列 PP 的完美數為:有多少個 ii 滿足 Pii=1|P_i-i|=1 。 求有多少個長度為 nn 的完美數恰好為 mm 的排列。

Solution

考慮容斥來做。具體地,設 s(k)s(k) 表示在 [1,n][1,n] 中選出 kk 個數,讓它們中的每一個數 ii 都滿足 Pii=1|P_i-i|=1 ,剩下的 nkn-k 個數隨便排的方案數。 那麼答案為: i=mn(1)imCims(i)\sum_{i=m}^n(-1)^{i-m}C_i^ms(i)

考慮通過 dp 求 ssf[i][j][0/1][0/1][0/1]f[i][j][0/1][0/1][0/1] 表示在 [1,i][1,i] 內選出 jj 個數放進 PP 裡面(滿足與自己的位置差的絕對值為 11 ),最後三維表示 Pi1P_{i-1}PiP_iPi+1P_{i+1} 三個位置是否已經有數填入。特別地,如果位置不存在則這一維只能為 00 。 邊界 f[0][0][0][0][0]=1f[0][0][0][0][0]=1 。 轉移(1): ii 不被放進 PP
內(作為剩下來的數隨便排)。 f[i+1][j][op2][op3][0]+=f[i][j][op1][op2][op3]f[i+1][j][op_2][op_3][0]+=f[i][j][op_1][op_2][op_3] 轉移(2):如果 i>0i>0ii 位置還沒有數則可以把 i+1i+1 放在 PiP_if[i+1][j+1][1][op3][0]+=f[i][j][op1][0][op3]f[i+1][j+1][1][op_3][0]+=f[i][j][op_1][0][op_3]
轉移(3):如果 i<n1i<n-1i+2i+2 位置還沒有數則可以把 i+1i+1 放在 Pi+2P_{i+2}f[i+1][j+1][op2][op3][1]+=f[i][j][op1][op2][op3]f[i+1][j+1][op_2][op_3][1]+=f[i][j][op_1][op_2][op_3] 如果在 nn 個數中選出 kk 個數使得其中每個數 ii 都滿足 Pii=1|P_i-i|=1 ,則在計算 s(k)s(k) 時剩下 nkn-k 個隨便排。 s(k)=(nk)!op1{0,1}op2{0,1}f[n][k][op1][op2][0]s(k)=(n-k)!\sum_{op_1\in\{0,1\}}\sum_{op_2\in\{0,1\}}f[n][k][op_1][op_2][0] 複雜度 O(n2)O(n^2)

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;

const int N = 1005, ZZQ = 1e9 + 7;
int n, m, fac[N], C[N][N], f[N][N][2][2][2], ans;

int main()
{
	int i, j, op1, op2, op3;
	cin >> n >> m;
	fac[0] = 1;
	For (i, 1, n) fac[i] = 1ll * fac[i - 1] * i % ZZQ;
	For (i, 0, n) C[i][0] = 1;
	For (i, 1, n) For (j, 1, i)
		C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % ZZQ;
	f[0][0][0][0][0] = 1;
	For (i, 0, n - 1) For (j, 0, i)
	{
		For (op1, 0, 1) For (op2, 0, 1) For (op3, 0, 1)
			(f[i + 1][j][op2][op3][0] += f[i][j][op1][op2][op3]) %= ZZQ;
		if (i > 0) For (op1, 0, 1) For (op3, 0, 1)
			(f[i + 1][j + 1][1][op3][0] += f[i][j][op1][0][op3]) %= ZZQ;
		if (i < n - 1) For (op1, 0, 1) For (op2, 0, 1) For (op3, 0, 1)
			(f[i + 1][j + 1][op2][op3][1] += f[i][j][op1][op2][op3]) %= ZZQ;
	}
	For (i, m, n)
	{
		int tmp = 0;
		For (op1, 0, 1) For (op2, 0, 1)
			tmp = (tmp + f[n][i][op1][op2][0]) % ZZQ;
		int delta = 1ll * tmp * fac[n - i] % ZZQ * C[i][m] % ZZQ;
		if (i - m & 1) ans = (ans - delta + ZZQ) % ZZQ;
		else ans = (ans + delta) % ZZQ;
	}
	cout << ans << endl;
	return 0;
}