HDU 4518 吉哥系列故事——最终数(自动机+数位DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4518

题意:定义数列F为包含大于10的斐波那契数的数组成的数列,F的前几项为13 ,21, 34, 55, 89,113,121,130,131...定义数列“最终数”为F中的斐波那契项组成的数列,“最终数”的前几项为:13,21,34,89……现在给出n,问“最终数”中与n最接近的数与n的绝对值。

思路:首先将斐波那契额数建立自动机,则给出n我们可以计算小于等于n有多少F数。那么首先计算一下n之前的F数设为t个,在斐波那契中找到t的大致位置x,那么我们要找出哪个数字ans之前的F数有Fib[x]个。二分查找该数。







struct node

{

    int next[10],fail,flag;



    void init()

    {

        clr(next,0);

        fail=0;

        flag=0;

    }





    void print()

    {

        int i;

        FOR0(i,10) printf("%d ",next[i]);

        printf("(%d %d)\n",fail,flag);

    }

};



node a[N];

int e;

i64 n;





void insert(int b[],int bNum)

{

    int i,k,p=0;

    for(i=bNum-1;i>=0;i--)

    {

        k=b[i];

        if(a[p].next[k]==0)

        {

            a[e].init();

            a[p].next[k]=e++;

        }

        p=a[p].next[k];

    }

    a[p].flag=1;

}



void insert(i64 x)

{

    int b[20],bNum=0;

    while(x)

    {

        b[bNum++]=x%10;

        x/=10;

    }

    insert(b,bNum);

}





queue<int> Q;



void build()

{

    int i,j,k,p,q;

    FOR0(i,10) if(a[0].next[i]) Q.push(a[0].next[i]);

    while(!Q.empty())

    {

        k=Q.front();

        Q.pop();

        for(i=0;i<10;i++)

        {

            if(a[k].next[i])

            {

                p=a[k].next[i];

                q=a[k].fail;

                Q.push(p);

                a[p].fail=a[q].next[i];

                a[p].flag|=a[a[p].fail].flag;

            }

            else

            {

                q=a[k].fail;

                a[k].next[i]=a[q].next[i];

            }

        }

    }

}





i64 f[20][N];

int b[20],bNum;

i64 F[65];



void init()

{

    F[0]=1;

    F[1]=2;

    int i;

    for(i=2;i<=60;i++) F[i]=F[i-1]+F[i-2];

}





i64 DFS(int id,int dep,int flag)

{

    if(dep==-1) return 1;

    if(!flag&&f[dep][id]!=-1) return f[dep][id];

    int i,R=flag?b[dep]:9;

    i64 ans=0;

    for(i=0;i<=R;i++)

    {

        if(a[a[id].next[i]].flag) continue;

        ans+=DFS(a[id].next[i],dep-1,flag&&i==R);

    }

    if(!flag) f[dep][id]=ans;

    return ans;

}



int cal(i64 x)

{

    i64 temp=x;

    bNum=0;

    while(x)

    {

        b[bNum++]=x%10;

        x/=10;

    }

    temp=temp+1-DFS(0,bNum-1,1);

    return upper_bound(F,F+60,temp)-F;

}



i64 find(i64 x)

{

    if(x==0) return -INF;

    i64 low=13,high=INF,mid;

    while(low<=high)

    {

        mid=(low+high)>>1;

        if(cal(mid)>=x) high=mid-1;

        else low=mid+1;

    }

    if(high>=13&&cal(high)>=x) return high;

    return low;

}





int main()

{

    init(); clr(f,-1); a[0].init();e=1;

    int i;

    for(i=5;i<=60;i++) insert(F[i]);

    build();

    while(scanf("%I64d",&n),n!=-1)

    {

        i=cal(n);

        PR(min(abs(n-find(i)),abs(n-find(i+1))));

    }

    return 0;

}

  

你可能感兴趣的:(HDU)