现在给出一个长度为N的一个01序列,每一轮游戏从左到右去改变值,第一个位子和最后一个位子上的数不会改变,其他位子的数,变成a【i】,a【i-1】,a【i+1】三个数中出现最多的那个数。问进行多少轮游戏能够不动 ,如果可以 ,输出游戏轮次以及最终序列的样子,否则输出-1.
思路:
①通过手写几种样例我们不难发现,结果是不存在-1的,换句话说,就是一定有解。
②根据观察我们也不难发现,只有01间隔的子串才会进行变化,对于一堆连在一起的0或者1来讲,其整个过程都不会进行改变。
那么我们很容易手写出几种情况:
长度为偶数:
1. 0101--->0011步数为1
2. 1010--->1100步数为1
长度为奇数:
3. 01010--->00000步数为2
4. 10101--->11111步数为2
③那么我们对于整个序列,只要找01间隔的最长的序列就能够确定游戏的轮次。Ans=Max((Len-1)/2);
然后对于每个间隔子串,进行处理即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int step;
int a[500500];
int ans[500500];
void Slove(int ss,int ee)
{
if(ee-ss+1==2)
{
ans[ss]=a[ss];
ans[ee]=a[ee];
return ;
}
step=max(step,((ee-ss+1)-1)/2);
if((ee-ss+1)%2==0)
{
for(int j=ss;j<=(ss+ee)/2;j++)ans[j]=0;
for(int j=(ss+ee)/2+1;j<=ee;j++)ans[j]=1;
if(a[ss]==1)for(int j=ss;j<=ee;j++)ans[j]=1-ans[j];
}
else
{
for(int j=ss;j<=ee;j++)ans[j]=0;
if(a[ss]==1)for(int j=ss;j<=ee;j++)ans[j]=1-ans[j];
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
step=0;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
ans[1]=a[1],ans[n]=a[n];
for(int i=1;i<n;i++)
{
if(a[i]==a[i+1])
{
ans[i]=a[i];
continue;
}
else
{
int ss=i;
int ee=i+1;
while(ee<n&&a[ee]!=a[ee+1])ee++;
Slove(ss,ee);
i=ee;
}
}
printf("%d\n",step);
for(int i=1;i<=n;i++)
{
printf("%d ",ans[i]);
}
printf("\n");
}
}