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);

    }

}

 

你可能感兴趣的:(bom)