1. 程式人生 > 實用技巧 >P3604 美好的每一天

P3604 美好的每一天

題目連結

https://ac.nowcoder.com/acm/contest/6885/D

題目大意

給定一個長度為 N 的序列 A , 保證它是一個 01 序列 , 並執行以下兩種操作 :

①、單點修改:將位置 X 上的數翻轉( 0 變 1 , 1 變 0)

②、字首修改:將位置 1 ~ X 上的數翻轉(每個數都 0 變 1 , 1 變 0)

問最少需要翻轉多少次,使得數列上所有數都變為 0

解題思路

我們定義 dp[i][0/1] 表示當前第 i 個位置 , 將前 i 個位置全變成 0 / 1 的最少運算元。

如果當前位置上 a[i] = 1,則:

dp[i][0] = min(dp[i - 1][0] + 1 , dp[i - 1][1] + 1) , 我們可以將a[i]單獨翻轉,也可以將這字首1一起翻轉;

dp[i][1] = min(dp[i - 1][1] , dp[i - 1][0] + 1) , 我們可以將字首0翻轉 , 然後把a[i]拼上去。

如果當前位置上a[i] = 0,則:

dp[i][0] = min(dp[i - 1][0] , dp[i - 1][1] + 1) , 我們可以將字首1翻轉 , 然後把a[i]拼上去;

dp[i][1] = min(dp[i - 1][0] + 1 , dp[i - 1][1] + 1) , 我們可以將a[i]單獨翻轉,也可以將這字首0一起翻轉;

答案為 dp[n][0] , 時間複雜度 O(n)。

AC_Code

#include<bits/stdc++.h>
using
namespace std; const int N = 1e5 + 10 , inf = 0x3f3f3f3f; int a[N] , dp[N][2]; signed main() { int n; cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> a[i] , dp[i][0] = dp[i][1] = inf; for(int i = 1 ; i <= n ; i ++) { if(a[i]) { dp[i][0] = min(dp[i - 1
][0] + 1 , dp[i - 1][1] + 1); dp[i][1] = min(dp[i - 1][1] , dp[i - 1][0] + 1); } else { dp[i][0] = min(dp[i - 1][0] , dp[i - 1][1] + 1); dp[i][1] = min(dp[i - 1][1] + 1 , dp[i - 1][0] + 1); } } cout << dp[n][0] << '\n'; return 0; }