P10160 [DTCPC 2024] Ultra 题解
【题目描述】
给你一个 \(01\) 序列,你可以进行如下操作若干次(或零次):
- 将序列中形如 \(101\cdots01\) 的一个子串(即 \(1(01)^k\),\(k\ge 1\))替换成等长的 \(010\cdots10\)(即 \(0(10)^k\))。
你要操作使得 \(1\) 的个数尽可能少,输出最少的 \(1\) 的个数。
【思路】
一开始看到这道题不会做,问老师,于是:
于是开始自己造数据,把结论玩出来了。
首先考虑这样子的情况:A00B
,\(A,B\) 是一个 \(01\) 序列。我们不难发现,对于这种情况,\(A,B\) 不管怎么替换,都不可能将 \(A,B\) 连在一起。于是我们有了第一步,将整个串分割开,分割条件是出现两个及以上连续的 \(0\)。
现在我们得到了一大堆 \(01\) 序列,这些序列都没有两个及以上连续的 \(0\)。对于每一个序列,可以分为两种情况:
- \(111\cdots111\):对于全部都是 \(1\) 的串,我们无法对其进行操作,答案加上区间长度。
- \(111\cdots101\cdots111\):对于其中至少有一个 \(0\) 的串,我们一定有一种方法让他只剩下一个 \(1\),答案加 \(1\)。证明过程放在最后。
于是这道题就做完了。
嗯。
【Code】
#include <bits/stdc++.h>
using namespace std;
char s[1000005];
int n,ans;
//判断是否是区间开始
bool Is_start(int x){
if(x==1&&s[x]=='1') return true;
if(x==2&&s[x-1]=='0'&&s[x]=='1') return true;
if(x>=3&&s[x-2]=='0'&&s[x-1]=='0'&&s[x]=='1') return true;
return false;
}
//判断是否为区间结束
bool Is_end(int x){
if(s[x]=='1'&&s[x+1]=='0'&&s[x+2]=='0') return true;
return false;
}
//判断一个区间中是否有 0
bool No_zero(int l,int r){
for(int i=l;i<=r;i++){
if(s[i]=='0') return false;
}return true;
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
s[n+1]=s[n+2]='0';
int l=0,r=0;
for(int i=1;i<=n;i++){
if(Is_start(i)) l=i; //是区间开始
if(Is_end(i)){ //是区间结束
r=i;
if(No_zero(l,r)) ans+=r-l+1; //全部是 1,无法消去
else ans+=1; //其中有 0,消到一个
}
}
printf("%d",ans);
return 0;
}
【证明】
证明内容:一个至少包含一个 \(0\) 的 \(01\) 串,最后一定可以被消除到只剩一个 \(1\)
我们从这个 \(01\) 串最右边的那个 \(0\) 开始。
那么这个串可以表示为 \(1\cdots1110111 \cdots 1A\) 的形式,\(A\) 是一个 \(01\) 串。
\(\begin{array}{c} \ \ \ \ \ \ \ \ {\color{Blue}1} \cdots {\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1} \cdots {\color{Blue}1}A \\ \Longrightarrow {\color{Blue}1} \cdots {\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1} \cdots {\color{Blue}1}A \\ \Longrightarrow {\color{Blue}1} \cdots {\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1} \cdots {\color{Blue}1}A \\ \Longrightarrow {\color{Blue}1} \cdots {\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0} \cdots {\color{Blue}1}A \end{array}\)
在替换的这个串的左边会碰到这个串的边缘:
\(\begin{array}{c} \ \ \ \ \ \ \ \ {\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0} \cdots A \\ \Longrightarrow {\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0} \cdots A \\ \Longrightarrow {\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Red}0}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Red}0}{\color{Red}0}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Red}0}{\color{Red}0}{\color{Red}0}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1} \cdots A \\ \end{array}\)
然后慢慢缩回来。
而它的右边则有两种情况:
-
碰到 \(1\),一起改变掉。
-
碰到 \(0\):
\(\begin{array}{c} \ \ \ \ \ \ \ \ {\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Blue}1} \cdots A \\ \Longrightarrow {\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1}{\color{Red}0}{\color{Blue}1} \cdots A \\ \end{array}\)