题意
给你一个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;
}