思路
首先有一個觀察:對於 \(a_i > 4\) 的行,一定只會用一次操作二,因為若要用操作一,那麼將 \(i,i + 1\) 都變白至少都需要 \(3\) 次操作,用操作二隻需要兩次。於是我們只考慮 \(a_i \le 4\) 的情況。
根據上面這個觀察,我們可以知道對於兩行 \(i,i + 1\) 放 \(2\) 個 \(2 \times 2\) 和用兩次操作二是等價的,於是對於放 \(2\) 個 \(2 \times 2\) 的行都將其換成用兩次操作二。那麼,每行就最多隻會有 \(1\) 個 \(2 \times 2\) 的方格,考慮其放在那裡(若存在):一定不會在 \(2\) 和 \(3\) 列之間,因為每一行的黑格子是從 \(1 \sim a_i\) 連續的,不能覆蓋 \(1\) 一定不優。故只會在 \(1,2\) 或 \(3,4\) 之間。記兩個 bool
變數 \(l,r\) 表示當前這一行的 \(1,2 / 3,4\) 是否被 \(2 \times 2\) 矩形覆蓋,方便進行答案計算。
接下來分類討論:
- \(a_i = 0\),不管它,跳過。
- \(l = 1\) 且 \(a_i \le 2\),此時這一行已經被覆蓋完,不用再操作。
- \(3 \le a_i \le 4\) 時:
- 若 \(l = 1\) 或 \(r = 1\),只需要在沒被覆蓋的那一邊放上一個 \(2 \times 2\) 的矩形即可,並將 \(l,r\) 都取反。
- 否則一定是用操作二將這行全覆蓋。為什麼?因為
不這樣寫過不了樣例根據上面的推論,在當前行放 \(2 \times 2\) 是與用兩個操作二等價的,還不如不用 \(2 \times 2\) 的矩陣,而是給下一行更多選擇機會,反正最劣也是再用一次操作二,更優的情況可能是 \(i + 1\) 行放 \(2 \times 2\) 省下一些步驟。
- \(1 \le a_i \le 2\),放一個 \(2 \times 2\) 在左邊,並 \(l \gets 1,r \gets 0\) 即可。
code
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int N = 2e5 + 5;
int a[N];
int n;
void solve(){
cin >> n;
for(int i = 1;i <= n;++ i) cin >> a[i];
int ans = 0;
bool l = 0,r = 0;
for(int i = 1;i <= n;++ i){
if(a[i] == 0 || (l && a[i] <= 2)){
l = r = 0;
continue;
}
if(a[i] > 4){
l = r = 0;
++ ans;
continue;
}
if(l || r){
++ ans;
swap(l,r);
continue;
}
if(a[i] > 2){
++ ans;
l = r = 0;
continue;
}
++ ans;
l = 1;r = 0;
}
cout << ans << endl;
}
int main(){
int _;
cin >> _;
while(_ --) solve();
return 0;
}
/*
1
4
3 2 1 0
*/