之前自己仿照紫书上写了高精度库,完善了乘法、减法,并且通过了和C++高精度库GMP的对拍测试,并在一些OJ上过了一些高精度的模板题,代码仓库地址:https://github.com/Edward-Elric233/BigInt

求解思路

题目的意思是求前100000斐波那契数列中某个前缀(不超过40个字符)第一次出现的位置。刚开始我的想法很简单,先求出这十万个斐波那契数列的前缀,然后每次读入的时候查找一遍就可以了,结果超时了。每次查找的复杂度是O(1e5∗40)O(1e5 * 40)O(1e5∗40),有5e4个样例,这样10s也会超时。

但是我发现这个数据结构只有查找操作,因此使用unordered_map再合适不过了。我将所有前缀保存在这个unordered_map中,每次查找近似都是O(1)O(1)O(1)的,因此肯定不会超时。

需要注意的是这里将前缀保存的时候需要将每个数字的所有前缀都保存,例如对于123,就要保存前缀112123

AC代码

// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2021/8/8
// Description:#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <iomanip>
#include <map>
#include <unordered_map>class BigInt {public:using ll = long long;static constexpr int BASE = 1e8;    //基数是1e8,即满1e8才进一位static constexpr int WIDTH = 8;     //每一位的十进制长度是8位,主要用于字符串和转换std::vector<int> bit;               //保存BigInt的每一位,小端模式:低位低字节,高位高字节bool negative;                      //记录数字是否是负数static void trim(std::string &s);                           //trim函数:删除头部和尾部的空格static void num2big(std::vector<int> &bit, ll num);         //实际处理函数:将正数num放入bit数组中static void str2big(std::vector<int> &bit, std::string &s); //实际处理函数:将正数字符串放入bit数组中static bool less(const BigInt &lhs, const BigInt &rhs);     //比较两个数字的绝对值的大小BigInt(ll num = 0);BigInt(std::string s); BigInt & operator =(ll num);         //必须返回BigInt&,与内置类型一致BigInt & operator =(std::string s);BigInt operator -() const;friend std::ostream &operator << (std::ostream &os, const BigInt &bigInt);friend std::istream &operator >> (std::istream &is, BigInt &bigInt);friend BigInt operator + (const BigInt &lhs, const BigInt &rhs);friend BigInt operator - (const BigInt &lhs, const BigInt &rhs);friend BigInt operator * (const BigInt &lhs, const BigInt &rhs);friend BigInt operator / (const BigInt &lhs, const BigInt &rhs);friend bool operator < (const BigInt &lhs, const BigInt &rhs);friend bool operator > (const BigInt &lhs, const BigInt &rhs);friend bool operator == (const BigInt &lhs, const BigInt &rhs);friend bool operator != (const BigInt &lhs, const BigInt &rhs);friend bool operator <= (const BigInt &lhs, const BigInt &rhs);friend bool operator >= (const BigInt &lhs, const BigInt &rhs);BigInt & operator += (const BigInt &rhs);BigInt & operator -= (const BigInt &rhs);BigInt & operator *= (const BigInt &rhs);BigInt & operator /= (const BigInt &rhs);std::string toString() const;BigInt & setOppo();                 //取相反数bool isNegative() const;            //判断是否是一个负数
};std::ostream & operator << (std::ostream &os, const BigInt &bigInt);
std::istream & operator >> (std::istream &is, BigInt &bigInt);
BigInt operator + (const BigInt &lhs, const BigInt &rhs);
BigInt operator - (const BigInt &lhs, const BigInt &rhs);
BigInt operator * (const BigInt &lhs, const BigInt &rhs);
BigInt operator / (const BigInt &lhs, const BigInt &rhs);
bool operator < (const BigInt &lhs, const BigInt &rhs);
bool operator > (const BigInt &lhs, const BigInt &rhs);
bool operator == (const BigInt &lhs, const BigInt &rhs);
bool operator != (const BigInt &lhs, const BigInt &rhs);
bool operator <= (const BigInt &lhs, const BigInt &rhs);
bool operator >= (const BigInt &lhs, const BigInt &rhs);BigInt BigInt::operator-() const {BigInt ret = *this;ret.negative = !ret.negative;return ret;
}BigInt & BigInt::setOppo() {negative = !negative;return *this;
}bool BigInt::isNegative() const {return negative;
}void BigInt::num2big(std::vector<int> &bit, ll num) {ll x;//必须使用do while,循环至少应该执行一遍,处理num是0的情况do {x = num % BASE;bit.push_back(static_cast<int>(x));num /= BASE;} while (num);
}BigInt::BigInt(ll num):negative(false) {if (num < 0) {num = -num;negative = true;}num2big(this->bit, num);
}void BigInt::str2big(std::vector<int> &bit, std::string &s) {int len = (s.size() - 1) / WIDTH + 1;       //ceil得到lenint start, end;for (int i = 0; i < len; ++i) {end = s.size() - i * WIDTH;start = std::max(0, end - WIDTH);bit.push_back(std::stoi(s.substr(start, end - start)));}
}BigInt::BigInt(std::string s):negative(false) {trim(s);if (s[0] == '-') {negative = true;s.erase(s.begin());}str2big(this->bit, s);
}void BigInt::trim(std::string &s) {auto ltrim = [](std::string &s) {s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char c) -> bool {//找到第一个非空字符return !std::isspace(c);}));};auto rtrim = [](std::string &s) {s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c) -> bool {//找到最后一个非空字符return !std::isspace(c);}).base(), s.end());};ltrim(s);rtrim(s);
}BigInt &BigInt::operator=(ll num) {bit.clear();negative = false;if (num < 0) {num = -num;negative = true;}num2big(this->bit, num);return *this;
}BigInt &BigInt::operator=(std::string s) {bit.clear();negative = false;trim(s);if (s[0] == '-') {negative = true;s.erase(s.begin());}str2big(this->bit, s);return *this;
}std::ostream &operator << (std::ostream &os, const BigInt &bigInt) {if (bigInt.negative) {//输出负号os << "-";}auto &bit = bigInt.bit;//以大端字节序输出os << bit.back();//除了最后一位,其他的如果有前导0不能忽略os << std::setfill('0');for (int i = bit.size() - 2; i >= 0; --i) {os << std::setw(BigInt::WIDTH) << bit[i];}os << std::setfill(' ');return os;
}std::istream &operator >> (std::istream &is, BigInt &bigInt) {std::string s;if (is >> s) {//必须判断是否读入成功bigInt = s;}return is;
}BigInt & BigInt::operator+=(const BigInt &rhs) {if (!negative && rhs.negative) {BigInt tmp = rhs;return *this = (tmp -= this->setOppo());} else if (negative && !rhs.negative) {return *this -= -rhs;}auto &rbit = rhs.bit;int max_len = std::max(bit.size(), rbit.size());int min_len = std::min(bit.size(), rbit.size());int g = 0;      //进位for (int i = 0; i < min_len; ++i) {bit[i] += rbit[i] + g;g = bit[i] / BASE;bit[i] %= BASE;}if (bit.size() < rbit.size()) {for (int i = min_len; i < max_len; ++i) {bit.push_back(g + rbit[i]);g = bit.back() / BASE;bit.back() %= BASE;}} else {for (int i = min_len; i < max_len; ++i) {bit[i] += g;g = bit[i] / BASE;bit[i] %= BASE;if (!g) break;}}if (g) {//加法的进位最多为1bit.push_back(g);}return *this;
}BigInt operator + (const BigInt &lhs, const BigInt &rhs) {BigInt ret = lhs;ret += rhs;return std::move(ret);
}BigInt & BigInt::operator-=(const BigInt &rhs) {if (!negative && !rhs.negative) {if (*this >= rhs) {} else {BigInt tmp = rhs;tmp -= *this;return *this = tmp.setOppo();}} else if (!negative && rhs.negative) {this->setOppo();*this += rhs;this->setOppo();return *this;} else if (negative && !rhs.negative) {return *this += -rhs;} else {BigInt tmp = -rhs;this->setOppo();return *this = (tmp -= *this);}auto &rbit = rhs.bit;for (int i = 0; i < rbit.size(); ++i) {if (bit[i] < rbit[i]) {bit[i] += BASE;bit[i + 1] -= 1;}bit[i] -= rbit[i];}for (int i = rbit.size(); i < bit.size(); ++i) {if (bit[i] >= 0) {break;}bit[i] += BASE;bit[i + 1] -= 1;}//删除前导0for (int i = bit.size() - 1; i > 0; --i) {if (!bit[i]) bit.pop_back();}return *this;
}BigInt operator - (const BigInt &lhs, const BigInt &rhs) {BigInt res = lhs;res -= rhs;return std::move(res);
}BigInt & BigInt::operator*=(const BigInt &rhs) {//负负得正if (negative && rhs.negative || !negative && !rhs.negative) {negative = false;} else {negative = true;}auto &rbit = rhs.bit;constexpr ll LBASE = BASE;std::vector<ll> c(bit.size() + rbit.size(), 0);for (int i = 0; i < bit.size(); ++i) {for (int j = 0; j < rbit.size(); ++j) {c[i + j] += static_cast<ll>(bit[i]) * static_cast<ll>(rbit[j]);//在这里处理进位防止溢出if (c[i + j] >= LBASE) {//有必要再进行除法,毕竟除法比较慢c[i + j + 1] += c[i + j] / LBASE;c[i + j] %= LBASE;}}}//处理进位for (int i = 0; i < c.size(); ++i) {if (c[i] >= LBASE) {//有必要再进行除法,毕竟除法比较慢c[i + 1] += c[i] / LBASE;c[i] %= LBASE;}}//删除前导0for (int i = c.size() - 1; i > 0; --i) {    //至少留一位if (!c[i]) c.pop_back();else break;}bit.resize(c.size());for (int i = 0; i < c.size(); ++i) {bit[i] = static_cast<int>(c[i]);}return *this;
}BigInt operator * (const BigInt &lhs, const BigInt &rhs) {BigInt res = lhs;res *= rhs;return std::move(res);
}std::string BigInt::toString() const {std::ostringstream os;os << *this;return os.str();
}bool BigInt::less(const BigInt &lhs, const BigInt &rhs) {if (lhs.bit.size() != rhs.bit.size()) return lhs.bit.size() < rhs.bit.size();for (int i = lhs.bit.size() - 1; i >= 0; --i) {if (lhs.bit[i] != rhs.bit[i]) return lhs.bit[i] < rhs.bit[i];}//相等return false;
}bool operator < (const BigInt &lhs, const BigInt &rhs) {if (!lhs.negative && !rhs.negative) {return BigInt::less(lhs, rhs);} else if (lhs.negative && !rhs.negative) {return true;} else if (!lhs.negative && rhs.negative) {return false;} else if (lhs.negative && rhs.negative) {//都是负数if (BigInt::less(lhs, rhs)) {return false;} else if (BigInt::less(rhs, lhs)) {return true;} else {return false;}}
}bool operator > (const BigInt &lhs, const BigInt &rhs) {return rhs < lhs;
}bool operator == (const BigInt &lhs, const BigInt &rhs) {return !(lhs < rhs) && !(rhs < lhs);
}
bool operator != (const BigInt &lhs, const BigInt &rhs) {return (lhs < rhs) || (rhs < lhs);
}bool operator <= (const BigInt &lhs, const BigInt &rhs) {return !(rhs < lhs);
}bool operator >= (const BigInt &lhs, const BigInt &rhs) {return !(lhs < rhs);
}using namespace std;constexpr int MAXN = 1e5;
vector<BigInt> fib;
unordered_map<string, int> str_hash;int main() {ios::sync_with_stdio(false);fib.push_back(1);fib.push_back(1);for (int i = 2; i < MAXN; ++i) {fib.push_back(fib[i - 1] + fib[i - 2]);}for (int i = 0; i < MAXN; ++i) {string line;auto &bit = fib[i].bit;line.append(to_string(bit.back()));for (int i = bit.size() - 2, j = std::max(0, int(bit.size()) - 6); i >= j; --i) {const string &number = to_string(bit[i]);for (int i = 0, j = 8 - number.size(); i < j; ++i) line.append("0");line.append(number);}
//        cout << line << endl;for (int ii = 1, jj = std::min(int(line.size()), 40); ii <= jj; ++ii) {const string &w = line.substr(0, ii);
//            cout << w << endl;if (str_hash.count(w)) {if (i < str_hash[w]) {str_hash[w] = i;}} else {str_hash[w] = i;}}}
//    for (int i = 0; i < 10; ++i) cout << fibHead[i] << " ";
//    cout << "\n";int T;cin >> T;string line;for (int caseI = 1; caseI <= T; ++caseI) {cin >> line;cout << "Case #" << caseI << ": ";if (str_hash.count(line)) {cout << str_hash[line] << "\n";} else {cout << "-1\n";}}
}

UVa-12333:Revenge of Fibonacci 高精度相关推荐

  1. HDU 4099 Revenge of Fibonacci (数学+字典数)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4099 这个题目就是一个坑或. 题意:给你不超过40的一串数字,问你这串数字是Fibonacci多少的开头 ...

  2. hdu 4099 Revenge of Fibonacci 字典树+大数

    将斐波那契的前100000个,每个的前40位都插入到字典树里(其他位数删掉),然后直接查询字典树就行. 此题坑点在于 1.字典树的深度不能太大,事实上,超过40在hdu就会MLE-- 2.若大数加法时 ...

  3. 紫书《算法竞赛入门经典》

    紫书<算法竞赛入门经典>题目一览 第3章 数组和字符串(例题) UVA 272 TEX Quotes UVA 10082 WERTYU UVA 401 Palindromes UVA 34 ...

  4. 斐波那契数列大数的压位c语言,HDU 1568 Fibonacci(大数前4位)

    分析:x=1234567.求其前四位数: log10(x)=log10(1.234567)+6. 所以1.234567=10^(log10(x)-6). 1234 =(int) 10^(log10(x ...

  5. HDU4099(斐波那契数列与字典树)

    题目:Revenge of Fibonacci 题意:给出斐波那契数列的前k位,k不超过40,找出最小的正整数n,满足F(n)的前k位与给定数的前k位相同,斐波那契数列的项数不超过100000. 解析 ...

  6. TYUT-A专题题解(一)

    TYUT-A专题题解(一) 01A Ad Hoc UVA353 LA5247 Pesky Palindromes[回文] - 海岛Blog - CSDN博客 UVA947 Master Mind He ...

  7. ACM程序设计基础题解

    ACM水题一 HDU1262 寻找素数对[素数] - 海岛Blog - CSDN博客 HDU4548 美素数[水题] - 海岛Blog - CSDN博客 HDU2503 a/b + c/d[水题] - ...

  8. ACM程序设计基础(2)题解

    ACM水题二 CodeForces-1A Theatre Square[水题] - 海岛Blog - CSDN博客 AOJ0009 Prime Number[筛选法+前缀和] - 海岛Blog - C ...

  9. π-Algorithmist分类题目(3)

    原题网站:Algorithmist,http://www.algorithmist.com/index.php/Main_Page π-Algorithmist分类题目(3) Probability ...

最新文章

  1. 这位创造GitHub冠军项目的“老男人”,堪称10倍程序员本尊
  2. 如何快速采集分析平台日志,并进行展示监控?
  3. nvidia驱动程序与windows版本不兼容
  4. Tracer Druid 记录sql 以及参数
  5. 5、jeecg 笔记之 minidao 条件判断
  6. Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)
  7. 1031. 查验身份证(15)-PAT乙级真题
  8. [Python]一步步安装numpy,matplotlib
  9. xpath抓取html不完全,scrapy的xpath是否取HTML标签的情况分析
  10. python 常用函数用法
  11. 放量十字星——黎明前的曙光还是黑暗前的夕阳
  12. [算法]LeetCode每日一题--9回文数(Java)
  13. boost::object_pool使用
  14. 期货开户线上线下开户流程
  15. 仪器数据自动化采集,助力提升实验室管理效率
  16. PSP版超级机器人大战A隐藏集体获得法(中文)
  17. GE Fanuc触摸屏维修ES0611人机界面维修详解
  18. java jframe 图片_java中JFrame添加背景图片
  19. s5pv210 i2c 时序
  20. 快消行业私域流量运营

热门文章

  1. HTML5 之 简单汇总
  2. sql查询语句for xml path语法
  3. pandas.read_csv参数详解
  4. iOS定时器-- NSTimer 和CADisplaylink
  5. Google SSL zz
  6. 关于重装系统后或打补丁后不能上网的问题的解决
  7. vi编辑器服务器维护,vi编辑器有哪几种工作模式及如何转换_网站服务器运行维护,vi编辑器,工作模式...
  8. 安装JAVA8要登录_JDK8的安装及环境配置
  9. python文件管理包_Python标准库04 文件管理 (部分os包,shutil包)
  10. 三个彩灯循环点亮程序_近百组彩灯点亮江畔,义渡灯会正式亮灯啦