HOJ 3555 Bomb 解题报告

/*
 * 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);
    }
}

 

posted @ 2013-05-15 01:21  SF-_-  阅读(200)  评论(0编辑  收藏  举报