POJ 3899 幸运数第一次积分赛H题

来源:互联网 发布:linux系统排行榜 2016 编辑:程序博客网 时间:2024/06/05 12:02
/*
    第一次积分赛的幸运数问题,很纠结的打出来了,然后找规律.

    这道题目还是真的没那么容易消化。。。

    题目地址:The Lucky Numbers

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>using namespace std;__int64 p[50];char str1[50], str2[50];__int64 cal1(char *a, char* b, int length)   //cal1(a,b,len) 表示1-a中后缀为b的lucky数,其中len是b的长度{          //表示后length位是b的,不大于a的Lucky Number总数。    __int64 ans = 0;    int len = strlen(a), i,flag=0;    for (i = 0; i < length; i++)      //为了求cal2时准备    {        int tt = i + len - length;        if (a[tt] > b[i])             break;        else if (a[tt] < b[i])        { flag=1; break; }    }    if (length == 0)      //把从4 7一直加到当前前一个.例如a的长度为3,则2+4加到2^3-2个       ans+= p[len]-2;    int m = len - length;   //表示后length位是b的,不大于a的Lucky Number总数。    for (i = 0; i < m; i++)    {        if (a[i] < '4')            break;        else if(a[i]>'4'&&a[i]<'7')        { ans+=p[m-i-1]; break; }  //确定之后,跳出循环        else if(a[i]=='7')          ans+=p[m-i-1];        else if(a[i]>'7')          { ans+=p[m-i]; break; }   //等于4等于7的时候需要继续向后判断    }    if(i==m&&!flag)       ans++;    return ans;}__int64 cal2(char *a, char *b)   //cal2(a,b)表示长度在1~a的长度中反转后大于b的lucky数{    __int64 ans = 0;    char mem[50], *last = &mem[49];    int len = strlen(a);    for (int i = 0; i < len; i++)    {        if (b[i] > '7') break;        else if (b[i] == '7') { *(last--) = '7'; }   else if (b[i] > '4' && b[i] < '7')        {  *last = '7';    ans += cal1(a, last, i + 1);    break;   }        else if (b[i] == '4')        {  *last = '7';    ans += cal1(a, last, i + 1);    *(last--) = '4'; }   else if (b[i] < '4')        {            *last = '7';    ans += cal1(a, last, i + 1);            *last = '4';    ans += cal1(a, last, i + 1); break;        }    }    return ans;}int main (){    int T,i;    p[0]=1;    for(i=1;i<=48;i++)       p[i]=p[i-1]<<1;    scanf("%d", &T);    while (T--)    {        cin>>str1>>str2;        int len1 = strlen(str1);        int len2 = strlen(str2);        if (str1[len1 - 1] != '0')            --str1[len1 - 1];        __int64 res = cal1(str2,NULL,0)-cal1(str1,NULL,0)+cal2(str2,str2)+cal2(str1, str1);        //算str1~str2的,所以先算1~str2的减去1~(str1-1).再加上两个之间可以经过变换得到的。        //反转之后才大于它的数目与反转之后才小于它的数目是相等的。        if (len1 == len2)           res -= cal2(str1,str2)*2;   //减去1~str1反转后才大于str2的,还有1~str2反转之后才小于st1的,两者数目也是相同的,故乘以2倍        printf("%I64d\n",res);    }    return 0;}


原创粉丝点击