Codeforces Round 1286A #612 (Div. 1) A. Garland 解题思路 - 思维题&贪心

博客讲述了Vadim如何解决关于装饰圣诞树中关于灯泡排列的复杂度问题,涉及到一个关于奇偶性的贪心算法。Vadim需要在确保灯泡复杂度最低的情况下,重新放置灯泡。复杂度定义为相邻灯泡奇偶性不同的数量。博客提供了输入输出说明,并解析了解题思路,包括不同情况的分析和最优解策略。

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

Codeforces Round #612 (Div. 1) A. Garland

Vadim loves decorating the Christmas tree, so he got a beautiful garland as a present. It consists of 𝑛 light bulbs in a single row. Each bulb has a number from 1 to 𝑛 (in arbitrary order), such that all the numbers are distinct. While Vadim was solving problems, his home Carp removed some light bulbs from the garland. Now Vadim wants to put them back on.
在这里插入图片描述

Vadim wants to put all bulb back on the garland. Vadim defines complexity of a garland to be the number of pairs of adjacent bulbs with numbers with different parity (remainder of the division by 2). For example, the complexity of 1 4 2 3 5 is 2 and the complexity of 1 3 5 7 6 4 2 is 1.

No one likes complexity, so Vadim wants to minimize the number of such pairs. Find the way to put all bulbs back on the garland, such that the complexity is as small as possible.

Input

The first line contains a single integer 𝑛(1≤𝑛≤100) — the number of light bulbs on the garland.

The second line contains 𝑛 integers 𝑝1, 𝑝2, …, 𝑝𝑛 (0≤𝑝𝑖≤𝑛) — the number on the 𝑖-th bulb, or 0 if it was removed.

Output

Output a single number — the minimum complexity of the garland.

Note

In the first example, one should place light bulbs as 1 5 4 2 3. In that case, the complexity would be equal to 2, because only (5,4) and (2,3) are the pairs of adjacent bulbs that have different parity.
In the second case, one of the correct answers is 1 7 3 5 6 4 2.

已知一串数字长度为n,由1到n的数字组成,每个数字出现一次,现在已知此串数字的某个位置的上的数字,其他不知道的位置由0表示。现在要求你把剩余的数字填上,保证总的相邻位置不相同的个数最小并输出这个最小数字。

解题思路:
因为只关乎奇偶性,所以先将所有的数字mod 2
最后的数字串类似以下(0表示mod2为0,1表示mod2为1,_表示空位):
_ _ 0 _ _ 121 _ _ 1111 _ _ 22212 _ _ 2212121 _ _ 1 _
对于以上则分为 _ _ 0,0 _ _ 1,1 _ _ 1,1 _ _ 2,2 _ _ 2,1 _ _ 1,1 _讨论
对于每一种情况:

  • 0 _ _ 1 :这样的情况不管填入什么一定会使最终的结果加1(或>1)。对于这样的情况的最优解是1,即只出现一段连续的0后再出现一段连续的1。
  • 1 _ _ 0 : 同上分析。
  • 1 _ _ 1 : 这样的情况最好是全部填1,最终的结果加0。但是如果1不够那么它一定会使最终的结果加2(或>2)。就是出现一段连续的1后再出现一段连续的0再出现一段连续的1(注意两端已经确定了一定是1)。
  • 0 _ _ 0 : 同上分析。
  • _ _ 0 : 这样的情况最好是全部填0,但是如果0不够那么它一定会使最终的结果加1(或>1)。就是出现一段连续的1后再出现一段连续的0。
  • 0 _ _ ,1 _ _ , _ _ 1:同上分析。

综合以上分析,就只需要一端数字和两端数字相同的情形(因为两端不同的最后最优化结果一定是使最终结果加1)。

考虑两端数字的情况会影响结果的大小为2,而一端的情况只有1。
并且考虑到一端的最多只有两个。
所以一定是优先填满两端(先按长度排序贪心):

  • 如果最后剩下只能填一个两端或者只能填一个一端,那么一定优先两端(此时两端优先于一端)
  • 如果最后剩下只能填一个两端或者只能填两个一端,那么选择两端或者两个一端(此时一样)
///@author zhaolu

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <set>
#include <map>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#include <sstream>
#include <algorithm>
#define rep(i,a,b) for(int i=a;i<b;++i)
#define repe(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define clc(a,b) memset(a,b,sizeof(a))
#define INF (0x3f3f3f3f)
#define MOD (1000000007)
#define MAX (100)
#define LEN (MAX+10)
typedef long long ll;
using namespace std;



struct node{
    int v;
    int len;
    inline bool const operator < (const node& obj) const{
        if(v!=obj.v) return v<obj.v;
        else return len<obj.len;
    }
}c[LEN];
int last, tmp, a, b, len, cc, ans;
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        b = n/2;
        a = n - b;
        len = cc = ans = 0;
        last = -1;
        for(int i = 0; i < n; ++i)
        {
            scanf("%d", &tmp);
            if(tmp&&tmp%2==1) a--;
            else if(tmp&&tmp%2==0) b--;

            if(tmp == 0) len++;
            else if(len==0)
            {
                if(last==-1);
                else if((last&1) !=  (tmp&1)) ans++;
                last = tmp;
                len = 0;
            }
            else
            {
                if(last == -1)
                {
                    if((tmp&1)==1) c[cc].v = 2;
                    else c[cc].v = 3;

                    c[cc++].len = len;
                }
                else if((last&1) ==  (tmp&1))
                {
                    if(last&1)  c[cc].v = 0;
                    else c[cc].v = 1;

                    c[cc++].len=len;
                }
                else
                {
                    c[cc].v = 4;
                    c[cc++].len=len;
                }
                last = tmp;
                len = 0;
            }

            
        }
        if(len)
            {
                if((last&1)==1) c[cc].v = 2;
                else c[cc].v = 3;
                c[cc++].len = len;
            }

            sort(c,c+cc);
            for(int i=0;i<cc;++i)
            {
                if(c[i].v==0)
                {
                    if(c[i].len<=a) a-=c[i].len;
                    else ans+=2;
                }
                else if(c[i].v==1)
                {
                    if(c[i].len<=b) b-=c[i].len;
                    else ans+=2;
                }
                else if(c[i].v==2)
                {
                    if(c[i].len<=a) a-=c[i].len;
                    else ans++;
                }
                else if(c[i].v==3)
                {
                    if(c[i].len<=b) b-=c[i].len;
                    else ans++;
                }
                else ans++;     
            }
            printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值