[原创]公平数的解法

公平数题解

百度之星的题目,是分值最多的,感觉不是很难,倒是分少的好难。

公平数 (35分)
问题背景
如果一个整数的十六进制表示(不含前导0)中,前一半数字之和等于后一半数字之和,我们称它为公平数。
注意,如果该数的十六进制表示中包含奇数个数字,则正中间的数字既不属于前一半,又不属于后一半。

例如在十六进制下1+D=7+7,因此1DE77是公平数。数字E并不参与计算。
再例如,所有单个数字的十六进制数(即0~F)均为公平数,但F0不是(不能把F0补充前导0写成0F0,进而认为它是公平数)。

给出十六进制数 K, X, Y 和十六进制数字集合 S,求区间[X, Y]之内,有多少个公平数满足:

十六进制表达式(不包含前导0)中每个数字均在集合S中
并且为K的倍数

输入格式
输入第一行为数字集S,包含0~9以及大写字母A~F。
每个数字或字母最多出现一次。
第二行包含 3 个十六进制正整数K, X, Y,均不超过 10 个数字(包含0~9以及大写字母A~F,不包含前导 0)。

输出格式
仅一行,包含一个整数,即满足条件的公平数个数。

样例输入
124C
5 100 FFF

样例输出
4

样例解释
只有四个数满足条件:212,424,4C4,C1C。

题解主要代码如下:

char int2char(int a)
{
    char b;
    if(a<=9&&a>=0)
        b=a+'0';
    else if(a>=10&&a<=15)
        b=a+'A'-10;
    else
        b=0;
    return b;
}

//求十六进制整数字符长度
int length(int i)
{
    char buff[11];
    sprintf(buff,"%x",i);
    string si(buff);
    return si.length();
}

//判断十六进制数字的字符是否都在字符集中
bool inset(int i,string charset)
{
    int j;
    while(i!=0)
    {
        int num = i%16;
        int pos = charset.find(int2char(num));
        if(pos==-1)
            return false;
        i /= 16;
    }
    return true;
}

//改进版如下,该版本除了判断该16进制数的字符是否为字符集中的外,还会寻找下一个可能的数字

//由于如果某高位不是字符集的字符,那么所有含该高位的数都是不符合的,因此下一个可能的数就是直接将该高位加1得到//的数(低于该位的数归零)

bool inset(long temp,string charset,long& i)
{
    int j=0;
    int highest=0;
    while(temp!=0)
    {
        ++j;
        int num = temp%16;
        int pos = charset.find(int2char(num));
        if(pos==-1)
            highest = j;
        temp /= 16;
    }
    if(highest==0)
        return true;
    else
    {
        temp = i;
        for(j=0;j<highest-1;j++)
        {
            i = i - temp%16*pow(16,j);
            temp /= 16;
        }
        i = i + pow(16,highest-1);
        return false;
    }
}
int main(int argc, char* argv[])
{
    string charset;
    int k,x,y;
    cin>>charset;
    scanf("%x %x %x",&k,&x,&y);
    sort(charset.begin(),charset.end());
    int i,j,sum=0;
    while(x%k!=0)
        ++x;
    for(i=x;i<=y;i+=k)
    {
        int temp = i;
        if(inset(temp,charset))//改进版改为inset(temp,charset,i)
        {
            int len = length(temp);
            int rsum=0,lsum=0;
            if(len!=1)
            {
                for(j=0;j<len/2;j++)
                {
                    rsum += temp%16;
                    temp /= 16;
                }
                if(len%2!=0)
                    temp /= 16;
                for(j=0;j<len/2;j++)
                {
                    lsum += temp%16;
                    temp /= 16;
                }
                if(rsum==lsum)
                {
                    sum++;
                    printf("%x\t",i);
                }
            }
            else
            {
                sum++;
            }
        }

        //改进版添加才需要如下代码

        else
        {
            while(i%k!=0)
                i++;
            i -= k;
        }

    }
    cout<<sum<<endl;

    return 0;
}

转载于:https://www.cnblogs.com/absolute8511/archive/2009/05/10/1649586.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值