zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    JAVA获取昨天、今天、明天等日期
    IDEA设置调用方法时提示方法上的注释
    Hibernate使用distinct返回不重复的数据,使用group by 进行分组
    SpringBoot 自定义注解
    tailwindcss 使用总结
    nodejs nvm 包管理
    macos NPM 全局安装解决方案
    git 遇到修改github密码导致本地push失败解决方案
    Jupyter 快捷方式设置
    Vue indent eslint缩进webstorm冲突解决
  • 原文地址:https://www.cnblogs.com/sbaof/p/3378072.html
Copyright © 2011-2022 走看看