传送门 https://codeforces.com/contest/1849/problem/D
D. Array Painting
题意
题解
分类讨论
这题的精髓在于欠债
用一个a0表示当前有没有负债
当前欠债最多为1
首先我们讨论, 在不欠债的情况下遇到0是怎么模拟的:
- 前面有能够产生贡献的12连通块
例如: 12110
很明显答案是1, 点亮左边这个连通块需要1块钱, 而此时2的左边没有负债, 所以没有产生额外的贡献当做1来看 - 前面没有能产生贡献的12连通块
例如: 1100 中下划线的0, 此时前一个0已经将此前的12连通块贡献给吸干了
这种情况, 负债a0+1
在负债的情况下遇到0:
- 前面存在2
例如: 01210
2既可以消除此前的负债, 又能担当起点亮这一串连通块的责任, 在例子中2作为12连通块的起点向两边走, 两边的0都可以被消去 - 前面不存在2
例如:01110
此时需要点亮左边12连通块, 把负债消去, 而现在遇到的这个0, 作为负债继续欠下去
需要注意的是, 如果遍历完了还有负债, 或者最后一个12连通块没有被点亮, 答案都需要+1
代码
void solve()
{
cin>>n;
vector<ll>a(n+1);
ans=0;
rep(i,1,n) cin>>a[i];
ll a1,a2,a0;
a1=a2=a0=0;
rep(i,1,n)
{
if(a[i]==1) a1=1;
else if(a[i]==2) a2=1;
else
{
if(a0)
{
if(a2)
{
//还上了, 但2节点必须要花一块
a0=0;
a1=0;
a2=0;
ans++;
}else
{
ans++;
//补上之前欠的, 继续欠
}
}else
{
if(a1||a2)
{
ans++;//染上上一个连续不为0的区块的色
a1=a2=0;
}else a0=1;//欠一个
}
}
}
if(a0||a[n]) ans++;
cout<<ans<<endl;
return;
}