HDU 4518 解题报告

来源:互联网 发布:淘宝象印官方旗舰店 编辑:程序博客网 时间:2024/04/19 21:47

1到1e11的斐波那契数很少,显然可以预处理出来。
然后枚举这些数,假设其为k,那么可以利用二分数位dp去查找第k个F数,calc(x)就是要求出1-x有多少个F数。
这里的问题是,怎么表示状态。
因为斐波那契数是字符串,而且数位dp是一个字符一个字符加上去的,无论是用map映射,还是hash数组,都不好转移,我们利用ac自动机里面,每个单词的结尾部分的节点值就表示这个单词,那么状态就完美解决了,惊奇的是,在数位dp做转移的时候也方便许多。
然后状态就是:dp[i][j][]。前i位,当前走到j节点,是否已经包含斐波那契数。

/*纳兰性德 -清《长相思·山一程》山一程,水一程,身向榆关那畔行,夜深千帐灯。风一更,雪一更,聒碎乡心梦不成,故园无此声。*///  Created by Matrix on 2016-02-02//  Copyright (c) 2015 Matrix. All rights reserved.//////#pragma comment(linker, "/STACK:102400000,102400000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <sstream>#include <set>#include <vector>#include <stack>#define ALL(x) x.begin(), x.end()#define INS(x) inserter(x, x,begin())#define ll long long#define CLR(x) memset(x, 0, sizeof x)using namespace std;const ll inf = 0x3f3f3f3f3f3f3f3f;const int MOD = 1e9 + 7;const int maxn = 1e6 + 10;const int maxv = 1e3 + 10;const double eps = 1e-9;const int Size = 10;int nxt[maxv][10];int have[maxv], fail[maxv];struct AcAmount {    int cnt;    int root;    int newNode() {        for(int i = 0; i < Size; i++) {            nxt[cnt][i] = -1;        }        have[cnt++] = 0;        return cnt - 1;    }    void init() {        cnt = 0;        root = newNode();    }    void insert(ll k) {        int digit[20];        int len = 0;        int now = root;        while(k) {            digit[len++] = k % 10;            k /= 10;        }        for(int i = len - 1; i >= 0; i--) {            int num = digit[i];            if(nxt[now][num] == -1) nxt[now][num] = newNode();            now = nxt[now][num];        }        have[now] = 1;    }    void build() {        fail[root] = root;        queue <int> que;        for(int i = 0; i < Size; i++) {            if(nxt[root][i] == -1) {                nxt[root][i] = root;            }            else {                fail[nxt[root][i]] = root;                que.push(nxt[root][i]);            }        }        while(que.size()) {            int u = que.front();            que.pop();            for(int i = 0; i < Size; i++) {                int &v = nxt[u][i];                if(v == -1) {                    v = nxt[fail[u]][i];                }                else {                    fail[v] = nxt[fail[u]][i];                    have[v] |= have[fail[v]];                    que.push(v);                }            }        }    }};ll fab[100];int tot;ll dp[20][maxv][2];ll digit[20];void Init() {    AcAmount ac;    ac.init();    tot = 2;    fab[1] = 1;    fab[2] = 1;    for(int i = 3; i < 100; i++) {        if(fab[i-1] + fab[i-2] > (ll)2e11) break;        fab[++tot] = fab[i-1] + fab[i-2];//      cout << fab[i] << endl;    }//  cout << tot <<endl;    for(int i = 1; i <= tot; i++) {        if(fab[i] < 10) continue;        ac.insert(fab[i]);    }    ac.build();    memset(dp, -1, sizeof dp);}ll dfs(int step, int pos, int flag, int limit) {    if(!step) return flag > 0;    if(!limit && dp[step][pos][flag] != -1) return dp[step][pos][flag];    ll ret = 0;    int up = limit ? digit[step] : 9;    for(int i = 0; i <= up; i++) {        int j = nxt[pos][i];        ret += dfs(step-1, j, have[j] | flag, limit && i == up);    }    if(!limit) dp[step][pos][flag] = ret;    return ret;}ll Calc(ll n) {    int cnt = 0;//  memset(dp, -1, sizeof dp);    while(n) {        digit[++cnt] = n % 10;        n /= 10;    }//  cout << tm << "********" << dfs(cnt, 0, 1) << endl;    return dfs(cnt, 0, 0, 1);}ll Find(ll n) {    ll l = 1, r = (ll)4e12;    while(l <= r) {        ll mid = (l + r) / 2;        ll num = Calc(mid);//        printf("mid = %lld  ", mid);//        printf("num = %lld\n", num);        if(num >= n) r = mid - 1;        else l = mid + 1;//        printf("l = %lld  r = %lld\n", l, r);    }//    printf("n = %lld  r = %lld\n", n, r);    return r + 1;}int main() {#ifdef LOCAL    freopen("in.txt", "r", stdin);//  freopen("out.txt","w",stdout);#endif    Init();    ll n;//  for(int i = 12; i <= 40; i++) {//          printf("i = %d  calc = %lld\n", i, Calc(i));//      }    while(scanf("%I64d", &n) != EOF && n != -1) {        ll ans = inf;        for(int i = 2; i <= tot; i++) {            ans = min(ans, abs(n - Find(fab[i])));        }        printf("%I64d\n", ans);//      for(int i = 1; i <= 3; i++) {//          printf("%d  %I64d\n", i, Find(i));//      }//      for(int i = 12; i <= 40; i++) {//          printf("i = %d  calc = %lld\n", i, Calc(i));//      }    }    return 0;}
0 0
原创粉丝点击