AWOI R2 C 数组操作
显然地,若要对
所以,我们将数组中等于
for(int i=1; i<=n; i++) a[i]=(read()==y);//true 表示红,false 表示蓝
for(int i=1; i<=n; i++) b[i]=(read()==y);//同上
先不考虑翻转操作和如何合并,假设合并后
容易发现,这张图至少需要
我们先考虑如何让数组
可以发现,执行以下两种操作若干次直到
- 取出
a 的前缀的若干个元素放入c 数组(后方元素向前移)。 - 取出
b 的前缀的若干个元素放入c 数组(后方元素向前移)。
意识到这点,我们就得到思路了:
- 将初始颜色段设为红色段。因为红色在前可以让更多的蓝色挨在一起。
- 若当前段是蓝色段,蓝色段计数器
s\gets s+1 。 - 找到
a 数组的前缀有多少个与该颜色段颜色相同,全部放入c 数组。 - 找到
b 数组的前缀有多少个与该颜色段颜色相同,全部放入c 数组。 - 变换为下一段颜色,重复第
2 步。
最终,
bool now=true;
int c1=0,c2=0,s=0;
while(1){
if(!now) s++;
while(a[c1+1]==now && c1+1<=n) c1++;
while(b[c2+1]==now && c2+1<=n) c2++;
if(c1==n && c2==n) break;
now=!now;
}
最优的合并策略已考虑,现在考虑最优翻转策略。由于答案是蓝色段的个数,所以翻转操作要让蓝色段数量减少。
我们选择一个红色段的左端点为
于是,我们可以发现,每一次的翻转都可以减少一个蓝色段!因此,若需要翻转的次数
有人可能有疑问:如果翻转到只剩一个蓝色段后(需要
还有一种特殊情况,就是输入的所有元素都是红元素(
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
bool a[N],b[N];
char *p1,*p2,buf[100000];
#define r() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read(){
int x=0,f=1;
char ch=r();
while(ch<48||ch>57){
if(ch=='-') f=-1;
ch=r();
}
while(ch>=48 && ch<=57) x=x*10+ch-48,ch=r();
return x*f;
}
int main(){
int n=read(),y=read(),z=read();
for(int i=1; i<=n; i++) a[i]=(read()==y);
for(int i=1; i<=n; i++) b[i]=(read()==y);
bool now=true;
int c1=0,c2=0,s=0;
while(1){
if(!now) s++;
while(a[c1+1]==now && c1+1<=n) c1++;
while(b[c2+1]==now && c2+1<=n) c2++;
if(c1==n && c2==n) break;
now=!now;
}
if(!s) cout<<0;
else if(s-1>=z) cout<<s-z;
else cout<<1;
return 0;
}