19牛客暑假多校B题 Shorten IPv6 Address(字符串模拟)

本文介绍了一种算法,用于将128位的二进制数转换为16进制,并在此基础上进行优化,通过省略连续的零来达到最短表示的目的。在多个可能的解决方案中,选择字典序最小的那一个。

题意

给你一个128位的01数,把它转换成16进制,然后去掉前缀零,然后连续的两个零以上就可以省略,但只能省略一个连续零串,问你怎么省略这个串最短,最短的串若有多个,输出字典序最小的那个。

思路

先把这个01串,每16位就转换成十进制,这样就能获得到八个十进制的值。最后我们输出的时候,用%x输出即可,这样子前缀零就自动去掉了,省事。

然后就是零串的选取,如果零串的长度不同,那么选取最长的那个零串,因为我们要压缩后尽可能短,在最短的前提下再输出字典序最小的。

然后就是零串的长度相同的时候,要看这个零串在整个串的哪个部分,是在中间还是在两端。
如果0串的长度相同,其中一个串在头部,那么我们肯定不取头部的那个,因为它的字典序不是最小的。
如果0串的长度相同,其中的一个在中间,另一个在尾部,那么我们要取中间的那个,因为省略了中间的零串后,字符串最短。
这里举例:在中部的零串(已经去掉前缀零了):0:0:省略后为::,长度少了3。而在尾部的零串:0:0,省略后为::,长度少了2。所以优先选中间的串。
如果中间有多个串长度相等,选取靠后的那个,这样字典序最小。

代码

#include<bits/stdc++.h>
using namespace std;
int a[10];
int main()
{
    int t;
    scanf("%d", &t);
    for(int cnt = 1; cnt <= t; ++cnt)
    {
        int first = 0, len = 0, nlen = 0, num = 0;
        for(int i = 1; i <= 8; ++i)
        {
            a[i] = 0;
            for(int j = 1; j<= 16; ++j)
            {
                scanf("%1d", &num);
                a[i] = (a[i] << 1) + num;
            }

            if(!a[i])
            {
                nlen++;
            }
            else//a[i]!=0
            {
                if(nlen >= 2 && nlen >= len)
                {
                    first = i - nlen;
                    len = nlen;
                }
                nlen = 0;
            }

            if(i == 8 && nlen >= 2)
            {
                if(nlen > len || (nlen == len && first == 1))
                {
                    first = i - nlen + 1;
                    len = nlen;
                }
            }
        }
        printf("Case #%d: ", cnt);
        if(first == 1)
            printf(":");
        for(int i = 1; i <= 8; i++)
        {
            if(i == first){
                printf(":");
                i += len;
            }
            if(i > 8)
                puts("");
            else
                printf("%x%c", a[i], ":\n"[i == 8]);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值