题解 P8100 【[USACO22JAN] Counting Haybales P】
纪念一下 usaco Pt 首次过两个题,C 完全没往凸包上想(
首先这个操作就是 swap 一对差为 1 的。
手玩一下容易发现如果两个元素差
那么只需要把不能 swap 的元素都从前往后连上边,就变成了一个 DAG 拓扑序计数问题。
但是一般的 DAG 拓扑序计数是不能做的,需要挖掘图的性质。差恰好为
现在就可以 DP 了,设
于是做完了,时空复杂度
#include <bits/stdc++.h>
using namespace std;
const long long mod = 1000000007;
long long dp[5005][5005];
int n, a[5005], pre[5005], pos[5005], idx[2][5005];
inline void Read() {
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
}
inline void Solve() {
int cnt[2] = {0};
memset(pre, 0, sizeof(pre));
memset(pos, 0, sizeof(pos));
memset(idx, 0, sizeof(idx));
for (int i = 1;i <= n;i++) {
pos[i] = ++cnt[a[i] & 1];
idx[a[i] & 1][cnt[a[i] & 1]] = i;
for (int j = i;j >= 1;j--) {
if (((a[i] ^ a[j]) & 1) && abs(a[i] - a[j]) != 1) {
pre[i] = j;
break;
}
}
}
for (int i = 0;i <= cnt[0];i++) {
for (int j = 0;j <= cnt[1];j++) dp[i][j] = 0;
}
dp[0][0] = 1;
for (int i = 0;i <= cnt[0];i++) {
for (int j = 0;j <= cnt[1];j++) {
if (pre[idx[0][i + 1]] <= idx[1][j]) dp[i + 1][j] = (dp[i + 1][j] + dp[i][j]) % mod;
if (pre[idx[1][j + 1]] <= idx[0][i]) dp[i][j + 1] = (dp[i][j + 1] + dp[i][j]) % mod;
}
}
cout << dp[cnt[0]][cnt[1]] << endl;
}
int main() {
int t; cin >> t;
while (t--) {
Read();
Solve();
}
return 0;
}