[Codeforces 285E]Positions in Permutations(容斥+DP)
阿新 • • 發佈:2018-12-11
Address
Meaning
稱一個 的排列 的完美數為:有多少個 滿足 。 求有多少個長度為 的完美數恰好為 的排列。
Solution
考慮容斥來做。具體地,設 表示在 中選出 個數,讓它們中的每一個數 都滿足 ,剩下的 個數隨便排的方案數。 那麼答案為: 考慮通過 dp 求 。 表示在 內選出 個數放進 裡面(滿足與自己的位置差的絕對值為 ),最後三維表示 , , 三個位置是否已經有數填入。特別地,如果位置不存在則這一維只能為 。 邊界 。 轉移(1): 不被放進 內(作為剩下來的數隨便排)。 轉移(2):如果 且 位置還沒有數則可以把 放在 。 轉移(3):如果 且 位置還沒有數則可以把 放在 。 如果在 個數中選出 個數使得其中每個數 都滿足 ,則在計算 時剩下 個隨便排。 複雜度 。
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;
}