cf360d题意:给定一个数组,有一个nn的网格。在第i行,从第一个到第ai个都是黑格子,剩下的是白格子。可以进行以下操作:将2×2子网格染白;将整行染白。找出将所有单元格染白的最少操作次数。
分析:如果ai>=5我们会想使用操作2,因为至少需要三个2×2的子网覆盖它,第i-1和i+1行不一定是黑格子,所以有可能浪费了。先考虑ai<=4的情况。
只右三种情况:不受上一行影响;涂前两格:涂后两格。
代码:(贪心)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void sol(){
int n;cin>>n;int a[n+10];
for(int i=1;i<=n;i++)cin>>a[i];
bool b1=0,b2=0;ll ans=0;
for(int i=1;i<=n;i++){
if((!b1)&&(!b2)){
if(a[i]==0)continue;
ans++;
if(a[i]<=2)b1=1;
}
else if(b1){
b1=0;
if(a[i]<=2)continue;
ans++;
if(a[i]<=4)b2=1;
}
else{
b2=0;
if(a[i]==0)continue;
ans++;
if(a[i]<=4)b1=1;
}
}
cout<<ans<<endl;
}
int main(){
int t;cin>>t;
while(t--)sol();
return 0;
}
(dp)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],dp[N];
void sol(){
int n;cin>>n;
int b[2]={N,N};
for(int i=1;i<=n;i++)cin>>a[i];
//b0=N,b1=N就是对下一行无影响
for(int i=1;i<=n;i++){
dp[i]=dp[i-1]+1;
if(a[i]==0)dp[i]=min(dp[i],dp[i-1]);
if(a[i]<=2)dp[i]=min(dp[i],i+b[1-i%2]);//上一个位置在奇数,现在在偶数,就可以减去1.反之一偶一奇也可以
if(a[i]<=2)b[i%2]=min(b[i%2],dp[i-1]-i);
else if(a[i]>4)b[0]=b[1]=N;
}
cout<<dp[n]<<endl;
}
int main(){
int t;cin>>t;
while(t--)sol();
return 0;
}