AT4515 [AGC030F] Permutation and Minimum
https://www.luogu.com.cn/problem/AT4515
肯定是先配对
把相邻的两个 分为几类
- ( a [ i ] , a [ i + 1 ] ) (a[i],a[i+1]) (a[i],a[i+1])两个都确定了,直接扔掉
- ( − 1 , − 1 ) (-1,-1) (−1,−1)记作第一类
- ( − 1 , a [ i + 1 ] ) (-1,a[i+1]) (−1,a[i+1])或 ( a [ i ] , − 1 ) (a[i],-1) (a[i],−1)记作第二类
然后从大到小填数,这样能保证每类只会在小的那个被计算,不重复不漏,没有后效性
然后我们来设状态
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示从大到小填了前 i i i个,有 j j j个第一类已经填了一个即 ( − 1 , x ) (-1,x) (−1,x),有 k k k个第二类
前不考虑
(
−
1
,
−
1
)
(-1,-1)
(−1,−1)的顺序,后面乘上个阶乘即可
然后考虑转移
-
i
i
i是属于第二类中的一个数
f [ i ] [ j ] [ k ] + = f [ i − 1 ] [ j + 1 ] [ k ] f[i][j][k]+=f[i-1][j+1][k] f[i][j][k]+=f[i−1][j+1][k]和一个第一类匹配
f [ i ] [ j ] [ k ] + = f [ i − 1 ] [ j ] [ k − 1 ] f[i][j][k]+=f[i-1][j][k-1] f[i][j][k]+=f[i−1][j][k−1]单独成一个第二类 - i i i没出现过
f
[
i
]
[
j
]
[
k
]
+
=
f
[
i
−
1
]
[
j
−
1
]
[
k
]
f[i][j][k]+=f[i-1][j-1][k]
f[i][j][k]+=f[i−1][j−1][k]单独成一个第一类
f
[
i
]
[
j
]
[
k
]
+
=
f
[
i
−
1
]
[
j
+
1
]
[
k
]
f[i][j][k]+=f[i-1][j+1][k]
f[i][j][k]+=f[i−1][j+1][k] 和一个第一类贴贴
f
[
i
]
[
j
]
[
k
]
+
=
f
[
i
−
1
]
[
j
]
[
k
+
1
]
∗
(
k
+
1
)
f[i][j][k]+=f[i-1][j][k+1]*(k+1)
f[i][j][k]+=f[i−1][j][k+1]∗(k+1) 选一个第二类的贴贴
代码很简单
code:
#include<bits/stdc++.h>
#define N 605
#define ll long long
#define mod 1000000007
using namespace std;
int n, a[N], ok[N], vis[N], gs, m;
ll f[2][N][N];
int main() {
scanf("%d", &n); n <<= 1;
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i += 2) {
if(min(a[i], a[i + 1]) != -1) vis[a[i]] = vis[a[i + 1]] = 1;
else {
if(max(a[i], a[i + 1]) == -1) ++ gs;
else ok[max(a[i], a[i + 1])] = 1;
}
}
for(int i = n; i >= 1; i --) if(!vis[i]) a[++ m] = i;
f[0][0][0] = 1;
int p = 1, q = 0;
for(int i = 1; i <= m; i ++, swap(p, q))
for(int j = 0; j <= n; j ++)
for(int k = 0; k <= n; k ++) {
f[p][j][k] = 0;
if(!ok[a[i]]) {
if(j) f[p][j][k] += f[q][j - 1][k];
f[p][j][k] += f[q][j + 1][k];
f[p][j][k] += f[q][j][k + 1] * (k + 1);
f[p][j][k] %= mod;
} else {
f[p][j][k] += f[q][j + 1][k];
if(k) f[p][j][k] += f[q][j][k - 1];
f[p][j][k] %= mod;
}
}
ll ans = f[m&1][0][0];
for(int i = 1; i <= gs; i ++) ans = ans * i % mod;
printf("%lld", ans);
return 0;
}