1. 程式人生 > >POJ 3899 幸運數第一次積分賽H題

POJ 3899 幸運數第一次積分賽H題

/*
    第一次積分賽的幸運數問題,很糾結的打出來了,然後找規律.

    這道題目還是真的沒那麼容易消化。。。

#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;
}