1800*2【Codeforces Round #612 (Div. 1) A】Garland
阿新 • • 發佈:2021-01-06
題目連結
翻譯
給你一個排列,其中有一些位置上的數字被remove了,讓你全都放回去。
定義相鄰兩個數字如果奇偶性不同,\(diff\) 值加 \(1\)。
求數字全都放回去之後 \(diff\) 的值的最小值。
題解
設 \(dp[i][j][k]\) 表示前 \(i\) 個數字放了 \(j\) 個偶數,最後一個數字奇偶性為 \(k\) 的最小 \(diff\)。
之所以可以只用偶數的個數來定義前 \(i\) 個的狀態,是因為它是一個排列。最後放完以後,偶數的個數是確定的。
而這個偶數具體是什麼對我們這道題而言不影響。所以我們只要關注奇偶性就好。
至於會不會出現哪個地方放進去偶數然後其實沒有足夠的偶數讓你用呢? 這種情況會被後面沒被移走的偶數做轉移的時候 exclude 掉的。
所以我們只要老老實實地記錄 \(j\) 個偶數最好的情況就行,至於這個狀態是不是合法的,沒有關係的。
最後輸出 \(dp[n][n/2][0]\) 和 \(dp[n][n/2][1]\) 中較小者即可。
時間複雜度 \(\mathcal{O}(N^2)\)
程式碼
#include <bits/stdc++.h> #define lson l,mid,rt*2 #define rson mid+1,r,rt*2+1 #define LL long long using namespace std; const int N = 100; //dp[i][j][k] 前 i 個位置,偶數個數有 j 個,最後一個位置奇偶性為k最小diff int dp[N+10][N+10][2]; int n,p[N+10]; int main(){ ios::sync_with_stdio(0),cin.tie(0); memset(dp,255,sizeof dp); for (int i = 0;i <= N; i++){ for (int j = 0;j <= N; j++){ for (int k = 0;k < 2; k++){ dp[i][j][k] = 1000; } } } dp[0][0][0] = dp[0][0][1] = 0; cin >> n; for (int i = 1;i <= n; i++){ cin >> p[i]; for (int j = 0;j <= i; j++){ if (j>0 && p[i]%2 == 0){ dp[i][j][0] = min(dp[i-1][j-1][1]+1,dp[i-1][j-1][0]); } if (p[i] == 0 || p[i]%2 == 1){ dp[i][j][1] = min(dp[i-1][j][0]+1,dp[i-1][j][1]); } } } cout << min(dp[n][n/2][0],dp[n][n/2][1]) << endl; return 0; }