UVa-12333:Revenge of Fibonacci 高精度
之前自己仿照紫書上寫了高精度庫(kù),完善了乘法、減法,并且通過(guò)了和C++高精度庫(kù)GMP的對(duì)拍測(cè)試,并在一些OJ上過(guò)了一些高精度的模板題,代碼倉(cāng)庫(kù)地址:https://github.com/Edward-Elric233/BigInt
求解思路
題目的意思是求前100000斐波那契數(shù)列中某個(gè)前綴(不超過(guò)40個(gè)字符)第一次出現(xiàn)的位置。剛開(kāi)始我的想法很簡(jiǎn)單,先求出這十萬(wàn)個(gè)斐波那契數(shù)列的前綴,然后每次讀入的時(shí)候查找一遍就可以了,結(jié)果超時(shí)了。每次查找的復(fù)雜度是O(1e5?40)O(1e5 * 40)O(1e5?40),有5e4個(gè)樣例,這樣10s也會(huì)超時(shí)。
但是我發(fā)現(xiàn)這個(gè)數(shù)據(jù)結(jié)構(gòu)只有查找操作,因此使用unordered_map再合適不過(guò)了。我將所有前綴保存在這個(gè)unordered_map中,每次查找近似都是O(1)O(1)O(1)的,因此肯定不會(huì)超時(shí)。
需要注意的是這里將前綴保存的時(shí)候需要將每個(gè)數(shù)字的所有前綴都保存,例如對(duì)于123,就要保存前綴1,12,123。
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; //基數(shù)是1e8,即滿1e8才進(jìn)一位static constexpr int WIDTH = 8; //每一位的十進(jìn)制長(zhǎng)度是8位,主要用于字符串和轉(zhuǎn)換std::vector<int> bit; //保存BigInt的每一位,小端模式:低位低字節(jié),高位高字節(jié)bool negative; //記錄數(shù)字是否是負(fù)數(shù)static void trim(std::string &s); //trim函數(shù):刪除頭部和尾部的空格static void num2big(std::vector<int> &bit, ll num); //實(shí)際處理函數(shù):將正數(shù)num放入bit數(shù)組中static void str2big(std::vector<int> &bit, std::string &s); //實(shí)際處理函數(shù):將正數(shù)字符串放入bit數(shù)組中static bool less(const BigInt &lhs, const BigInt &rhs); //比較兩個(gè)數(shù)字的絕對(duì)值的大小BigInt(ll num = 0);BigInt(std::string s); BigInt & operator =(ll num); //必須返回BigInt&,與內(nèi)置類型一致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(); //取相反數(shù)bool isNegative() const; //判斷是否是一個(gè)負(fù)數(shù) };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,循環(huán)至少應(yīng)該執(zhí)行一遍,處理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 {//找到第一個(gè)非空字符return !std::isspace(c);}));};auto rtrim = [](std::string &s) {s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c) -> bool {//找到最后一個(gè)非空字符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) {//輸出負(fù)號(hào)os << "-";}auto &bit = bigInt.bit;//以大端字節(jié)序輸出os << bit.back();//除了最后一位,其他的如果有前導(dǎo)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; //進(jìn)位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) {//加法的進(jìn)位最多為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;}//刪除前導(dǎo)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) {//負(fù)負(fù)得正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]);//在這里處理進(jìn)位防止溢出if (c[i + j] >= LBASE) {//有必要再進(jìn)行除法,畢竟除法比較慢c[i + j + 1] += c[i + j] / LBASE;c[i + j] %= LBASE;}}}//處理進(jìn)位for (int i = 0; i < c.size(); ++i) {if (c[i] >= LBASE) {//有必要再進(jìn)行除法,畢竟除法比較慢c[i + 1] += c[i] / LBASE;c[i] %= LBASE;}}//刪除前導(dǎo)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) {//都是負(fù)數(shù)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";}} }總結(jié)
以上是生活随笔為你收集整理的UVa-12333:Revenge of Fibonacci 高精度的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 海信冰箱使用说明书现在冷藏调到多少度合适
- 下一篇: vim命令笔记