Loading

【题解】[Codechef] Beautiful Permutation

传送门

以此纪念我场切的 dp。

这种计数的类型一看就很 dp 的样子。考场上一开始设的 dp 状态是 \(dp_{i,j,k_1,k_2,0/1}\) 表示将前 \(i\)个数分为 \(j\) 段,放了 \(k_1\) 个偶数,\(k_2\) 个奇数,当前段为偶数段或奇数段的方案数。考虑如何转移,记 \(cnt_0\) 表示序列中可填入的偶数个数,\(cnt_1\) 表示序列中可填入的奇数个数。

\(i\) 为空时,可以写出四个转移:

\[dp_{i,j,k_1,k_2,0} = (cnt_0-k_1+1)(dp_{i-1,j,k_1-1,k_2,0} + dp_{i-1,j-1,k_1-1,k_2,1}) \]

\[dp_{i,j,k_1,k_2,1}=(cnt_1-k_2+1)(dp_{i-1,j,k_1,k_2-1,1} + dp_{i-1,j-1,k_1,k_2-1,0}) \]

\(i\) 为非空时,可以根据 \(a_i\) 的奇偶性写出两个转移:

\[dp_{i,j,k_1,k_2,0} = dp_{i-1,j,k_1,k_2,1} + dp_{i-1,j-1,k_1,k_2,0} (a_i 为奇数) \]

\[dp_{i,j,k_1,k_2,1} = dp_{i-1,j-1,k_1,k_2,1} + dp_{i-1,j,k_1,k_2,0} (a_i 为偶数) \]

可以把第一维滚掉,这样就做到了时间复杂度 \(O(n^4)\),空间复杂度 \(O(4n^3)\)。70分到手。

我们发现记前 \(i\) 个数中空位为 \(sum_i\) 个,则填了 \(k_2\) 个奇数时必然填了 \(sum_i-k_2\) 个偶数。偶数的数量可以被奇数固定下来,于是重新设状态 \(dp_{i,j,k_2,0/1}\) 表示将前 \(i\)个数分为 \(j\) 段,\(k_2\) 个奇数,当前段为偶数段或奇数段的方案数。则转移变为:

\(i\) 为空时:

\[dp_{i,j,k_2,0} = (cnt_0-(sum_i-k_2)+1)(dp_{i-1,j,k_2,0} + dp_{i-1,j-1,k_2,1}) \]

\[dp_{i,j,k_2,1}=(cnt_1-k_2+1)(dp_{i-1,j,k_2-1,1} + dp_{i-1,j-1,k_2-1,0}) \]

\(i\) 为非空时:

\[dp_{i,j,k_2,0} = dp_{i-1,j,k_2,1} + dp_{i-1,j-1,k_2,0} (a_i 为奇数) \]

\[dp_{i,j,k_2,1} = dp_{i-1,j-1,k_2,1} + dp_{i-1,j,k_2,0} (a_i 为偶数) \]

时间复杂度为 \(O(n^3)\),空间复杂度 \(O(2n^3)\)。可通过此题。

#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 1000000007

using namespace std;

const int N = 305;

int n, m, a[N], cnt[N], dp[N][N][N][2], sum;

signed main() {
  freopen("2475.in", "r", stdin);
  freopen("2475.out", "w", stdout);
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n >> m;
  For(i,1,n) {
    cin >> a[i];
    if(!a[i]) continue;
    cnt[a[i] & 1]++;
  }
  cnt[0] = n / 2 - cnt[0];
  cnt[1] = ceil(1.0 * n / 2) - cnt[1];
  dp[0][0][0][0] = dp[0][0][0][1] = 1;
  For(i,1,n) {
    if(!a[i]) sum++;
    For(j,1,m) {
      For(k2,0,min(sum, cnt[1])) {
        if(a[i] != 0) {
          if(a[i] & 1) {
            dp[i][j][k2][1] = (dp[i][j][k2][1] + (dp[i-1][j-1][k2][0] + dp[i-1][j][k2][1]) % mod) % mod;
          } else {
            dp[i][j][k2][0] = (dp[i][j][k2][0] + (dp[i-1][j][k2][0] + dp[i-1][j-1][k2][1]) % mod) % mod;
          }
          continue;
        }
        if(cnt[0] - (sum - k2) + 1 > 0) dp[i][j][k2][0] = (dp[i][j][k2][0] + ((cnt[0] - (sum - k2) + 1) * (dp[i-1][j-1][k2][1] + dp[i-1][j][k2][0]) % mod) % mod) % mod;
        if(k2 != 0) dp[i][j][k2][1] = (dp[i][j][k2][1] + ((cnt[1] - k2 + 1) * (dp[i-1][j-1][k2-1][0] + dp[i-1][j][k2-1][1]) % mod) % mod) % mod;
      }
    }
  }
  cout << (dp[n][m][cnt[1]][0] + dp[n][m][cnt[1]][1]) % mod << '\n';
  return 0;
}
posted @ 2024-10-18 16:58  Daniel_yzy  阅读(6)  评论(0编辑  收藏  举报