AT_abc134_f Permutation Oddness 题解

题目链接

一道有意思的题目。

题目大意

【数据删除】

Sol

可以把问题转化成二分图匹配,将 \(i\)\(p_i\) 进行匹配,则每一条边的贡献也就是中间跨过的距离。

考虑DP。定义 \(f[i][j][k]\) 表示 \(i\) 位置,还有 \(j\) 组没有匹配,目前的总贡献为 \(k\)。答案显然为 \(f[n][0][k]\)

则考虑三种转移:

  • 匹配一组。则 \(f[i][j][k] = f[i-1][j][k - 2j] \times (j*2+1)\),其中 \(k - 2 \times j\) 是因为考虑上面的点,对于那些没有得到匹配的点,往下一步,必然会使答案多 \(2 * j\)。然后后面的系数,是考虑左部点匹配,右部点匹配,自己与自己匹配。
  • 匹配两组,则 \(f[i][j][k] = f[i-1][j+1][k-2j] \times (j+1)^2\),这里 \((j+1)^2\) ,是因为左部点和右部点不能互连,同时都要连接上面的 \(j+1\) 个空缺。
  • 不匹配,则 \(f[i][j][k] = f[i-1][j-1][k-2j]\)
    然后就做完了。

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define fi first
#define se second
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
const int N = 105;
LL f[2][N][N * N / 2];
int n,K;
const LL mod = 1e9 + 7;
int main()
{
	IOS;
	cin >> n >> K;
	f[0][0][0] = 1;
	int pre,nw;
	pre = 0,nw = 1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=n;j++){
			for(int k=2 * j;k<=K;k++){
				if(j == 0) f[nw][j][k] = f[pre][j][k - 2 * j] % mod + f[pre][j+1][k - 2 * j] * (j + 1) * (j + 1) % mod;
				else f[nw][j][k] = f[pre][j][k - 2 * j] * (j * 2 + 1) % mod + f[pre][j+1][k - 2 * j] * (j + 1) * (j + 1) % mod + f[pre][j-1][k - 2 * j];
				f[nw][j][k] %= mod;
			}
		}
		swap(pre,nw);
	}
	cout << f[pre][0][K];
	return 0;
}

后记

点名表扬这篇题解,代码与所推转移对不上。好在还是看出。

内容疑似由人类生成,请注意甄别。

posted @ 2026-03-31 16:05  WinterXorSnow  阅读(2)  评论(0)    收藏  举报