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;
}
后记
点名表扬这篇题解,代码与所推转移对不上。好在还是看出。
内容疑似由人类生成,请注意甄别。

浙公网安备 33010602011771号