高精度题解:1745 天使的起誓(yubikili)

背景

本题收藏于某OJ题库的高精度算法题单,解法参考SSL_wj 的题解,稍有改进。

原题

1745: 天使的起誓(yubikili)

题目描述

TENSHI非常幸运的被选为掌管智慧之匙的天使。在正式任职之前,她必须和其他新当选的天使一样,要宣誓。宣誓仪式是每位天使各自表述自己的使 命,她们的发言稿被放在N个呈圆形排列的宝盒中。这些宝盒按顺时针方向被编上号码1、2、3……、N-1、N。一开始天使们站在编号为N的宝盒旁。她们各 自手上都有一个数字,代表她们自己的发言稿所在的盒子是从1号盒子开始按顺时针方向的第几个。例如:有7个盒子,那么如果TENSHI手上的数字为9,那 么她的发言稿所在盒子就是第2个。现在天使们开始按照自己手上的数字来找发言稿,先找到的就可以先发言。TENSHI一下子就找到了,于是她最先上台宣 誓:“我将带领大家开启NOI之门……”TENSHI宣誓结束以后,陆续有天使上台宣誓。可以有一位天使找了好久都找不到她的发言稿,原来她手上的数字M 非常大,她转了好久都找不到她想找的宝盒。 任务:请帮助这位天使找到她想找的宝盒的编号。

输入格式

输入文件有一行分别正整数N和M,其中N、M满足

2 ≤ N ≤ 10E8,2 ≤ M ≤ 10E1000

输出格式

只有一行即宝盒的编号。

样例输入

7 9

样例输出

2

思路

这道题就是高精除以高精的一道高精度典型例题(M的范围太大了,都有1000位了,用低精度的除法肯定不行),即疯狂进行高精度减法,直到不能减为止,详细参见本文(这篇文章还没写好,写好了链接上)。

但是但是!!!有一个非常重要的问题,TLE(Time Limit Exceed)!!!因为位数太多,普通除肯定会超时,所以引入移位补零的思想。

移位具体

因为本题方法是高精求余,所以可以先用乘整十、整百、整千……的得数来减 (详细见下文的例子),此时余下的数据规模就会减小很多,再减法求余,便省去大量时间成本。

例如:15000÷600,先转化成 15000-6000×2 -> 15000-12000 = 30000,再不断地用3000减去600,得出结果200(是不是简单了许多)

AC Code

#include <iostream>
#include <string>
using namespace std;

const int MAX = 1010;    //常量定义数组大小
int a[MAX], b[MAX], c[MAX];
string str1, str2;

void jian() {    //高精度减法模板
    for (int i = MAX - 1; i > 0; i--) {
        if (a[i] < b[i])    a[i - 1]--, a[i] += 10;
        a[i] -= b[i];
    }
}
bool com(int *a, int *b) {    //大小比较,判断数组a还能不能继续减,不能返回0
    int i = 0;
    while (a[i] == b[i] && i < MAX)    i++;
    if (i == MAX)    return true;
    else    return a[i] >= b[i];
}
void print() {    //去除前导0并输出
    int i = 1;
    while (a[i] == 0 && i < MAX)    i++;
    if (i == MAX)    cout << str1;
    else for (int j = i; j < MAX; j++)    cout << a[j];
}
void chu() {    //★灵魂@_@ 高精除+移位处理 (不然TLE)
    int j = 1;
    while (com(a, b)) {
        j++;
        for (int i = 2; i < MAX; i++) {
            b[i - 1] = b[i];
            b[i] = 0;
        }
    }
    while (j > 0) {
        while (com(a, b))    jian();
        j--;
        for (int i = MAX - 1; i > 0; i--)
            b[i] = b[i - 1], b[i - 1] = 0;
    }
}
void input() {    //输入并对齐(带前导零)存储
    cin >> str1 >> str2;
    for (int i = 0; i < str1.size(); i++)
        b[MAX - str1.size() + i] = str1[i] - '0';
    for (int i = 0; i < str2.size(); i++)
        a[MAX - str2.size() + i] = str2[i] - '0';
    if (com(a, b) == 0 || com(b, a) == 0)    chu();
    //判断是否进行除法运算处理
}
int main() {
    input();    print();
    return 0;
}

小技巧

想让你的代码变得整齐有序?格式化来帮你!

本人用的DEV C++格式化快捷键是Ctrl+Shift+A,格式化之后代码缩进整齐有序、运算符之间都有空格,强迫症狂喜ing...(这个没法撤回哦)

本期分享就到这里了,掰掰ヾ(•ω•`)o

本文可以转载,但请注明作者,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值