hdu 4518 【AC自动机+数位DP+二分】

这个题刚看完题,觉得应该很难!但仔细想想还是应该有思路的(虽然确实挺难的)

题意:

在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱。现在,它又在思考一个关于斐波那契的问题:
  假如我们现在已知斐波那契数是1,1,2,3,5,8,13,21,34,55,89...
  由于吉哥特别喜欢斐波那契数,它希望每个数中都包含斐波那契数,比如说130,其中包含了13,或者5534包含了55和34,只要数位中含有至少一个斐波那契数就是吉哥想要的数。但是这种数实在太多了,于是它去掉那些仅仅含有小于10的斐波那契数的数,比如说1,仅仅含有1,所以被去掉;或者335只含有3和5,都是小于10的斐波那契数,所以也去掉;但是131是留下的,因为它含有13,我们暂且称这类数为F数,不难得到前几个F数是 13 ,21, 34, 55, 89,113,121,130,131...
  霸气的吉哥觉得这样还不够,它想将斐波那契进行到底――在前面F数的基础上,吉哥要得到那些是第斐波那契数个的F数!就是说,我们假设F数从1开始标号,那么13是第1个F数,吉哥想要那些在F数中的排列或者说下标也要是斐波那契数的数,吉哥称之为最终数,如13,21,34,89,130...
  现在给你一个数n,吉哥想知道离n最近的最终数与n的差的绝对值是多少。

思路:至少存在一个通常会转化成一个也不存在。查找一个后缀是否有或者没有一个子串,AC自动机最好。先求出n之前有多少个F数。然后在非波那切数组中查找,到底有多少个最终数记为st。

          然后二分的找出第st个和st+1个最终数。

 

//#pragma comment(linker, "/STACK:102400000")
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<vector>
#define tree int o,int l,int r
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lo o<<1
#define ro o<<1|1
#define pb push_back
#define mp make_pair
#define ULL unsigned long long
#define LL long long
#define inf 0x7fffffff
#define eps 1e-7
#define N 409
#define M 10
using namespace std;
int m,n,T,t,cnt;
int ch[N][M],v[N],sz;
int f[N],last[N];
LL val;
char s[30];
LL d[N][20],ans;
void init()
{
    sz=1;
    memset(ch[0],0,sizeof(ch[0]));
    memset(v,0,sizeof(v));
    memset(last,0,sizeof(last));
    memset(d,-1,sizeof(d));
}
int idx(char c)
{
    return c-'0';
}
void insert(char str[],int val)
{
    int u=0;
    for(int i=0; str[i]; i++)
    {
        int c=idx(str[i]);
        if(!ch[u][c])
        {
            memset(ch[sz],0,sizeof(ch[sz]));
            ch[u][c]=sz++;
        }
        u=ch[u][c];
    }
    v[u]=val;
}
void getac()
{
    f[0]=0;
    queue<int>q;
    for(int c=0; c<M; c++)
    {
        int u=ch[0][c];
        if(u)
        {
            f[u]=0;
            q.push(u);
            last[u]=v[u];//////////////////
        }
    }
    while(!q.empty())
    {
        int r=q.front();
        q.pop();
        for(int c=0; c<M; c++)
        {
            int u=ch[r][c];
            if(!u)
            {
                ch[r][c]=ch[f[r]][c];
            }
            else
            {
                q.push(u);
                int s=f[r];
                f[u]=ch[s][c];
                last[u]=(v[u]||last[f[u]]);/////////////////
            }
        }
    }
}
LL fa[100]= {0,1,1};
void ff()
{
    init();
    char str[20];
    int a=0,b=1,c=2;
    cnt=2;
    while(fa[a]+fa[b]<=(LL)1e12)
    {
        fa[c]=fa[a]+fa[b];
        cout<<"##fa[c]="<<fa[c]<<endl;

        if(fa[c]>=10)
        {
            sprintf(str,"%I64d",fa[c]);
            insert(str,1);
        }
        c=(c+1);
        a=(a+1);
        b=(b+1);
    }
    cnt=c;
    getac();
}
LL dp(int u,int len,int up)
{
    if(len==0)return 1;
    if(!up&&d[u][len]!=-1)return d[u][len];
    LL ans=0;
    int end=up?idx(s[n-len]):9;

    for(int i=0; i<=end; i++)
    {
        int c=ch[u][i];
        if(last[c]==0)
            ans+=dp(c,len-1,up&&i==end);
    }
    if(!up)d[u][len]=ans;
    return ans;
}
LL find(LL x)
{
    LL l=13,r=1e12;
    while(l<r)
    {
        LL mid=(l+r)>>1;
        sprintf(s,"%I64d",mid);
        n=strlen(s);
        if(mid+1-dp(0,n,1)<x)
            l=mid+1;
        else
            r=mid;
    }
    return l;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ex.in","r",stdin);
#endif
    ff();
    while(scanf("%I64d",&val)==1&&val!=-1)
    {
        sprintf(s,"%I64d",val);
        n=strlen(s);
        LL num=dp(0,n,1);
        num=val+1-num;
        LL x,y;

        for(int i=1; i<cnt; i++)
        {
            if(fa[i]>num)
            {
                x=fa[i-1];
                y=fa[i];
                break;
            }
        }

        LL l=find(x);
        LL r=find(y);
        if(fa[1]>num)
            ans=r-val;
        else
            ans=min(val-l,r-val);
        printf("%I64d\n",ans);
    }
    return 0;
}

 

 

转载于:https://www.cnblogs.com/sbaof/p/3378072.html

标题基于Python的自主学习系统后端设计与实现AI更换标题第1章引言介绍自主学习系统的研究背景、意义、现状以及本文的研究方法和创新点。1.1研究背景与意义阐述自主学习系统在教育技术领域的重要性和应用价值。1.2国内外研究现状分析国内外在自主学习系统后端技术方面的研究进展。1.3研究方法与创新点概述本文采用Python技术栈的设计方法和系统创新点。第2章相关理论与技术总结自主学习系统后端开发的相关理论和技术基础。2.1自主学习系统理论阐述自主学习系统的定义、特征和理论基础。2.2Python后端技术栈介绍DjangoFlask等Python后端框架及其适用场景。2.3数据库技术讨论关系型和非关系型数据库在系统中的应用方案。第3章系统设计与实现详细介绍自主学习系统后端的设计方案和实现过程。3.1系统架构设计提出基于微服务的系统架构设计方案。3.2核心模块设计详细说明用户管理、学习资源管理、进度跟踪等核心模块设计。3.3关键技术实现阐述个性化推荐算法、学习行为分析等关键技术的实现。第4章系统测试与评估对系统进行功能测试和性能评估。4.1测试环境与方法介绍测试环境配置和采用的测试方法。4.2功能测试结果展示各功能模块的测试结果和问题修复情况。4.3性能评估分析分析系统在高并发等场景下的性能表现。第5章结论与展望总结研究成果并提出未来改进方向。5.1研究结论概括系统设计的主要成果和技术创新。5.2未来展望指出系统局限性并提出后续优化方向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值