/* * HOJ 3555 Bomb * 花了一晚上时间写的,感觉还是值得的,方法都是自己想的 * 定义d[i][0]为长度是 i 不含49子串的不以4结尾的串的数量 * 定义d[i][1]为长度是 i 不含49子串的以4结尾的串的数量 * 则易知 * d[i][0]=d[i-1][1]*8(除去4,9)+d[i-1][1]*9(除去4) * d[i][1]=d[i-1][0]+d[i-1][1] * 基于此,推出针对小于n的数中不含49子串的串的数量的方法 * 例如45,我们从左往右扫,遇到4,则d[0][1]=1,d[0][0]=4(0,1,2,3) * 遇到5,则d[1][1]=d[0][1]+d[0][0]=5(04,14,24,34,44) * d[1][0]=d[i-1][1]*8(40,41,42,43,45,46,47,48)+d[i-1][1]*9(01,02,03,05,,,09,10,,,19,,,39) * -3(前一位是4,不能匹配9和4了,8-5=3) * 同理可得当前一位不是4时,做相似处理。 * 当数字中包含49时,很难搞了,直接像上面这样做是错的,原因可以自己试试 * 我们统计的是不含49的串,最后总数减去即可,故可以将XX49XXX处理成XX48999 * 中间的推倒过程繁琐了点。。。 */ #include <iostream> #include <string.h> using namespace std; long long R1[]={7,6,5,4,4,3,2,1,0,0}; long long R2[]={8,7,6,5,5,4,3,2,1,0}; long long d[100][2]; int main() { // freopen("in.txt","r",stdin); int cas,i,len; long long ans; char p[200]; scanf("%d",&cas); while(cas--) { memset(d,0,sizeof(d)); scanf("%I64d",&ans); sprintf(p,"%I64d",ans); len=strlen(p); p[0]-='0'; for(i=1;i<len;i++) { p[i] -= '0'; if( p[i] == 9 && p[i-1] == 4 ) { p[i] = 8; for( i++; i < len; i++ ) p[i] = 9 ; } } d[0][0] = p[0] + 1 ; if( d[0][0] > 4 ) { d[0][0] -- ; d[0][1] = 1 ; } for(i=1;i<len;i++) { d[i][1] = d[i-1][0] + d[i-1][1] + ( p[i] < 4 ? -1 : 0 ); d[i][0] = d[i-1][0] * 9 + d[i-1][1] * 8 - ( p[i-1] == 4 ? R1[ p[i] ] : R2[ p[i] ] ); } ans++; ans-=d[i-1][1]+d[i-1][0]; printf("%I64d\n",ans); } }