IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> UVa-12333:Revenge of Fibonacci 高精度 -> 正文阅读

[C++知识库]UVa-12333:Revenge of Fibonacci 高精度

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

求解思路

题目的意思是求前100000斐波那契数列中某个前缀(不超过40个字符)第一次出现的位置。刚开始我的想法很简单,先求出这十万个斐波那契数列的前缀,然后每次读入的时候查找一遍就可以了,结果超时了。每次查找的复杂度是 O ( 1 e 5 ? 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得到len
    int 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) {
        //加法的进位最多为1
        bit.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;
    }
    //删除前导0
    for (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;
        }
    }
    //删除前导0
    for (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";
        }
    }
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:03:37  更:2021-08-09 10:06:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 11:29:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码