ABC134_F Permutation Oddness

· · 个人记录

ABC134_F Permutation Oddness

题目连接

一道想到就不难的dp。

首先看数据范围, n \le 50 ,一个说大不大说小不小的让人难受的范围。。。

那么状压也肯定不行,考虑把每个数的贡献独立出来。

对于一个数 i 来说,他所放的位置有三种情况:

  1. 放在第 i 位前面

这个时候,他的贡献要么是 i + i (放在第 i 位的数小于 i ),或者是 i - i (放在第 i 位的数大于 i )。

  1. 放在第 i 位

此时贡献只能为 0 。

  1. 放在第 i 位后面

这时,他的贡献就是 - i + i (放在第 i 位的数小于 i ),或者是 - i - i (放在第 i 位的数大于 i ) 。

所以说,与一个数 i 有关的贡献就是 第 i 位的那个下标,以及 i 这个数本身。

但是因为还要确定 i 能不能放到前面,或者第 i 位能不能放比 i 小的数,所以状态中还要多一维,表示有多少个位置是空的,其实也就是有多少个数没放。

那么转移有点多,见代码。 ```cpp #include <cstdio> #include <cctype> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define reg register #define rep(i, a, b) for (reg int i = (a), i##end = (b); i <= i##end; ++i) #define dep(i, a, b) for (reg int i = (a), i##end = (b); i >= i##end; --i) template <typename _typer> inline _typer read() { _typer init = 0; char ch = getchar(), k = 0; for ( ; !isdigit(ch); ch = getchar()) k = (ch == '-'); for ( ; isdigit(ch); ch = getchar()) init = (init << 3) + (init << 1) + (ch ^ 48); return k ? -init : init; } const ll N = 55, INF = 1e9; const ll M = 5005, Mod = 1e9 + 7; int n, m; ll f[N][N][M]; int main() { n = read<int>(), m = read<int>(); f[0][0][2500] = 1; rep (i, 0, n - 1) { rep (j, 0, i) rep (k, 0, 5000) { // 1 选一个空位放并且选一个数放自己这 if (j > 0 && k + 2 * i <= 5000) (f[i + 1][j - 1][k + 2 * i] += f[i][j][k] * j * j) %= Mod; // 2 选一个空位放i,然后自己空出来 (f[i + 1][j][k] += f[i][j][k] * j) %= Mod; // 3 放自己 (f[i + 1][j][k] += f[i][j][k]) %= Mod; // 4 选一个放自己这,然后空位不变 (f[i + 1][j][k] += f[i][j][k] * j) %= Mod; // 5 自己空出来 if (k - 2 * i >= 0) (f[i + 1][j + 1][k - 2 * i] += f[i][j][k]) %= Mod; } } // 每个数都放了 cout << f[n][0][2500 + m] << endl; return 0; } ```