题解:AT_joisc2019_h ランプ (Lamps)

题意

走廊上有排成一列的 n 盏灯,给出了一个 01S 表示其开关状态(1 表示打开,0 表示关闭)。现在想要把这 n 盏灯变成目标状态 T

你有三种操作:

  • OFF 操作:选择一个区间,将区间内所有的灯关闭。
  • ON 操作:选择一个区间,将区间内所有的灯打开。
  • TOG 操作:选择一个区间,在区间内关闭原本打开的灯,打开原本关闭的灯。

求将灯的状态从 S 变为 T 的最小的操作数。

分析

首先,任意两个有交的翻转操作 [l1,r1][l2,r2](其中 l1l2)可以化成两个不交的翻转操作 [l1,l2)(r1,r2]

所以在最优情况下存在翻转操作互不相交的方案。


然后考虑覆盖操作。

首先显然覆盖操作的区间要么不交,要么一个包含另一个。

正确性显然。

后一种情况可以化为先覆盖再翻转,所以存在覆盖操作互不相交的方案。


最后考虑覆盖操作和翻转操作之间的关系。

如果是先翻转再覆盖,此时翻转区间一定包含覆盖区间。

那么就可以先覆盖相反的值,然后再翻转。


所以存在覆盖操作互不相交,且翻转操作互不相交,且先覆盖再翻转的方案。

据此,可以进行线性 dp。

dpi,v(v{0,1,2}) 为考虑到第 i 位,其覆盖结果分别为用 0 覆盖、用 1 覆盖、不覆盖所需的最少操作数。

分情况讨论是否需要添加翻转即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000006
int dp[maxn][3];
char S[maxn], T[maxn];
int main()
{
int n;
scanf("%d%s%s", &n, S+1, T+1);
dp[1][0]=(T[1]!='0')+1;
dp[1][1]=(T[1]!='1')+1;
dp[1][2]=(T[1]!=S[1]);
for(int i=2;i<=n;i++)
dp[i][1]=min({dp[i-1][0]+(T[i]!='1')*(T[i-1]=='0')+1, dp[i-1][1]+(T[i]!='1')*(T[i-1]=='1'), dp[i-1][2]+(T[i]!='1')*(T[i-1]==S[i-1])+1}),
dp[i][0]=min({dp[i-1][0]+(T[i]!='0')*(T[i-1]=='0'), dp[i-1][1]+(T[i]!='0')*(T[i-1]=='1')+1, dp[i-1][2]+(T[i]!='0')*(T[i-1]==S[i-1])+1}),
dp[i][2]=min({dp[i-1][0]+(S[i]!=T[i])*(T[i-1]=='0'), dp[i-1][1]+(S[i]!=T[i])*(T[i-1]=='1'), dp[i-1][2]+(S[i]!=T[i])*(S[i-1]==T[i-1])});
printf("%d\n", min({dp[n][0], dp[n][1], dp[n][2]}));
}

本文作者:Jimmy-LEEE

本文链接:https://www.cnblogs.com/redacted-area/p/18379537

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jimmy-LEEE  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起