POJ 3899 幸運數第一次積分賽H題
阿新 • • 發佈:2019-01-05
/*
第一次積分賽的幸運數問題,很糾結的打出來了,然後找規律.
第一次積分賽的幸運數問題,很糾結的打出來了,然後找規律.
這道題目還是真的沒那麼容易消化。。。
#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; }