Codeforces Round #327 (Div. 2)——C. Median Smoothing

本文解析了一道关于01串变化的算法题,通过分析01串的变化规律,总结出奇数和偶数长度01串所需变化次数的计算方法,并提供了一个具体的C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

现在有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
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值