题意:
现在有n个数字,然后对于这n个数字,它的首和尾是不会发生变化的,然后对于中间的i从2~n-1的数,b[i]的值为a[i-1],a[i],a[i+1]的中位数。然后问你最少进行几次变化,使得b[i]都不会发生变化了,并且输出b[i]的值。
思路:
想了好久,没有理清思路,首先我们要知道对于一个串,它会发生变化当且它是一个01这种类型的串,因为0与1相互间隔时才会需要交换。其实只要发现了这点,题目就很简单了。
01串的交换是有规律的:
1)当01串的长度是奇数时,我们要改变的次数为len/2+1
2)当01串的长度是偶数时,因为我们每次进行的改变都会使01串最左边的和最右边的变成和左边的那个和右边那个相等的数字,所以其实就像是从两边向中间包围。
例如:
0 1 0 1 0 1 0 1
0 0 1 0 1 0 1 1
0 0 0 1 0 1 1 1
0 0 0 0 1 1 1 1
看到了吗?每次变化都会使首末变成和它周围相同的那个数。
所以需要改变的次数为 len/2
然后for一遍取最大值就好了。
至于保存路径,我是保存了起点和终点来写的。因为对于01串我们可以知道它最后会变成什么数字,所以直接存下来就好了。
#include<stdio.h>
#include<vector>
#include<map>
#include<cmath>
#include<queue>
#include<string.h>
#include<iostream>
using namespace std;
#define maxn 500010
int a[maxn],ans[maxn],vis[maxn];
struct node{
int s,e;
int len;
}t[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int len=0,lmax=0,cnt=0;
for(int i=2;i<n;i++){
if(a[i]!=a[i-1]&&a[i]!=a[i+1]){
vis[i]=1;
if(len==0) t[cnt].s=i;
len++;
if(i==n-1) t[cnt].e=i,t[cnt++].len=len;
}
else{
if(len!=0){
t[cnt].e=i-1;
t[cnt++].len=len;
}
len=0;
}
}
for(int i=0;i<cnt;i++) t[i].e=t[i].s+t[i].len-1;
for(int i=0;i<cnt;i++){
if(t[i].len%2) lmax=max(lmax,t[i].len/2+1);
else lmax=max(lmax,t[i].len/2);
}
printf("%d\n",lmax);
if(lmax==0){
for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?'\n':' ');
return 0;
}
int cc=0,tot=0;
for(int i=1;i<=n;i++){
if(!vis[i]){
ans[tot++]=a[i];
continue;
}
else if(i>t[cc].e) cc++;
if(t[cc].s<=i&&i<=t[cc].e){
if(t[cc].len%2){
int tt=t[cc].s-1;
ans[tot++]=a[tt];
}
else{
if(i<=t[cc].s+t[cc].len/2-1){
ans[tot++]=a[t[cc].s-1];
}
else ans[tot++]=a[t[cc].e+1];
}
}
}
for(int i=0;i<tot;i++){
if(i!=tot-1) printf("%d ",ans[i]);
else printf("%d\n",ans[i]);
}
}
/*
5
0 1 0 1 0
*/