zoukankan      html  css  js  c++  java
  • HDU 4518

    整理一下思路,明天再写。。。

     这道题,其实就是求包含大于10的斐波那切数字的第K(K是斐波那契数)个数。注意到斐波那契数的爆炸性增长,所以在范围 内的符合要求的F数并不多吧。比如求第K个F数,那么,前K个F数都是这样的数,组成它们的数字中有斐波那契数。这就是字符串匹配吧。把这些数转化成字符串匹配,也就是很经典的数位DP,求范围内含有这些数字的数有多少个。

    但是,所要含的数有很多个,怎么样匹配呢?转化成字符串,构成AC自动机来做。但是,说实话,求含有数字的个数确实不好弄,没关系,把它转化成不含有就容易了。于是,就成了AC自动机+数位DP了。但是,我们要求的是第K个,那么,因为个数是单调增的,求出刚好第K个可以使用二分查找来办到。

    使用AC自动机来做数位DP,首先要构建trie图,然后明白哪些状态是可转移或不可转移的,然后在trie图上进行DP就可以了。

    dp[i][j],即是当前是前第i位数位,并处在自动机的j状态上。

    #include <iostream>
    #include <cstdio>
    #define LL __int64
    using namespace std;
    
    const LL inf=10000000000000ll;
    const int root=0;
    LL f[60],ans[60];
    
    int trie[550][10],bit[30],fail[550],que[550],head,tail;
    int tot;
    int nxt[550][10];
    LL dp[15][550];
    bool tag[550];
    
    void insert(LL now){
        int len=0;
        while(now){
            bit[++len]=now%10;
            now/=10;
        }
        int p=root,i=len;
        while(i--){
            if(trie[p][bit[i+1]]==-1){
                trie[p][bit[i+1]]=++tot;
            }
            p=trie[p][bit[i+1]];
        }
        tag[p]=true;
    }
    
    void build_ac(){
        head=tail=0;
        que[tail++]=root;
        while(head!=tail){
            int tmp=que[head++];
            int p=-1;
            for(int i=0;i<10;i++){
                if(trie[tmp][i]!=-1){
                    if(tmp==root) fail[trie[tmp][i]]=root;
                    else{
                        p=fail[tmp];
                        while(p!=-1){
                            if(trie[p][i]!=-1){
                                fail[trie[tmp][i]]=trie[p][i];
                                break;
                            }
                            p=fail[p];
                        }
                        if(p==-1) fail[trie[tmp][i]]=root;
                    }
                    if(tag[fail[trie[tmp][i]]]) tag[trie[tmp][i]]=tag[fail[trie[tmp][i]]];
                    que[tail++]=trie[tmp][i];
                }
                else{
                    if(tmp==root) trie[tmp][i]=root;
                    else{
                        p=fail[tmp];
                        while(p!=-1){
                            if(trie[p][i]!=-1){
                                trie[tmp][i]=trie[p][i];
                                break;
                            }
                            p=fail[p];
                        }
                        if(p==-1) trie[tmp][i]=root;
                    }
                }
            }
        }
    }
    
    LL dfs(int len,int j,bool flag){
        if(len==0) return 1ll;
        if(!flag&&dp[len][j]!=-1) return dp[len][j];
        LL ans=0;
        int up=flag?bit[len]:9;
        for(int i=0;i<=up;i++){
            if(tag[nxt[j][i]]||nxt[j][i]==-1) continue;
            ans+=dfs(len-1,nxt[j][i],i==up&&flag);
        }
        if(!flag) dp[len][j]=ans;
        return ans;
    }
    
    LL cal(LL m){
        LL tm=m+1ll;
        int len=0;
        while(m){
            bit[++len]=m%10;
            m/=10;
        }
        return tm-dfs(len,0,true);
    //    return 0;
    }
    
    LL bin(LL num){
    //    cout<<cal(13)<<endl;
    //    system("pause");
        LL l=0,r=inf,ret=-1,tmp;
        while(l<=r){
            LL m=(l+r)>>1;
            if((tmp=cal(m))>=num){
                r=m-1;
                ret=m;
    //            cout<<m<<endl;
            }
            else l=m+1;
        }
        return ret;
    }
    
    int cal_next(int p,int j){
        if(tag[p]) return -1;
        if(tag[trie[p][j]]) return -1;
        return trie[p][j];
    }
    
    void Init(){
        tot=0;
        memset(trie,-1,sizeof(trie));
        memset(tag,false,sizeof(tag));
        memset(fail,-1,sizeof(fail));
        f[1]=1ll; f[2]=1ll;
        for(int i=3;i<=55;i++){
            f[i]=f[i-1]+f[i-2];
            if(f[i]>10){
                insert(f[i]);
            }
        }
        build_ac();
        for(int i=0;i<=tot;i++){
            for(int j=0;j<10;j++)
            nxt[i][j]=cal_next(i,j);
        }
        memset(dp,-1,sizeof(dp));
        int c=0;
        for(int i=2;i<=55;i++){
            ans[c]=bin(f[i]);
    //        system("pause");
            if(ans[c]==-1) break;
            c++;
    //        printf("%I64d  %d
    ",ans[c-1],c);
        }
    }
    
    int main(){
        Init();
        LL n;
    //    cout<<"YES"<<endl;
        while(scanf("%I64d",&n)!=EOF&&n!=-1){
            LL ret=inf;
            for(int i=0;i<54;i++){
                LL tmp=n-ans[i];
            //    cout<<tmp<<endl;
                if(tmp<0) tmp=-tmp;
                if(ret>tmp) ret=tmp;
            }
            printf("%I64d
    ",ret);
        }
        return 0;
    }
  • 相关阅读:
    SAP MM 采购附加费计入物料成本之二
    SAP MM 采购附加费计入物料成本?
    SAP MM 作为采购附加费的运费为啥没能在收货的时候计入物料成本?
    SAP MM 外部采购流程里的Advanced Return Management
    SAP MM 外部采购流程里的如同鸡肋一样的Advanced Returns Management功能
    SAP MM Why is the freight not included in the material cost at the time of GR?
    SAP MM: Change of material moving average price after goods receipt and invoice verification posting for PO
    SAP 创建启用了ARM功能的采购订单,报错 Shipping processing is not selected to supplier 100057 in purchase org. 0002
    GIT·代码仓库默认分支更改
    .Net/C#·运行报错缺少XXX文件,但双击无法跳转缺少位置
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4338630.html
Copyright © 2011-2022 走看看