【快速乘与快速幂例题讲解】相乘取余爆long long?试试快速乘吧!

就在昨天,笔者正在愉快的刷着牛客的比赛,然后,我遇到了这样一题
学长的白日梦

20级的学弟学妹们来了,实验室里可怜弱小又无助的wzc学弟终于变成了学长,可以压迫下一级了(?)。
但是wzc学长苦于自己的实力进步太慢,很担心自己在学弟学妹们面前丢人,所以天天熬夜在实验室里训练。
某一天wzc学长训练得实在太累了,居然在大白天做起了梦。
在梦里面,wzc学长在第一天有一个初始的码力值x,第二天的时候码力值变为了x2,第三天的时候码力值变为了x3......第i天的时候码力值变为了xi。
现在wzc学长想知道第i天的时候,他的码力值是多少。由于这个值可能非常大,请输出对9999999967取模的结果。
输入描述:
第一行一个整数T,代表输入数据组数。(1≤T≤1×103)
接下来T行,每行两个整数x和i,代表第一天的初始码力值,和所要求的是第几天的码力值。
(1≤x≤10,不会吧不会吧,不会真的有人这么弱吧)
(1≤i≤1×109)

输出描述:
输出T行,每行一个整数,代表xi对9999999967取模的结果。

示例1
输入
2
1 1000000000
2 3

输出
1
8

飞快的读完题,笔者心里暗喜,哈哈,这不就是考一个快速幂吗?(不会吧不会吧,不会真的有人还不会快速幂吧----->【快速幂】csdn博客

然后,笔者自信爆棚的敲下了自认为完美的代码

#include<iostream>

#define ll long long
using namespace std;
ll n = 9999999967;
ll t;

ll qmi(ll x, ll i)
{
	ll ans=1;
	ll k = x%n;
	while (i)
	{
		if (i & 1)
		{
			ans = ans  *( k % n);
		}
		i >>=1;
		k = k * k%n;
	}
	return ans;
}
int main()
{
	cin >> t;
	while (t--)
	{
		ll x, i;
		cin >> x >> i;
		cout << qmi(x, i) << endl;
	}
	return 0;
}

提交!然后…wa了?

喵喵喵????这怎么可能???!我取模的部分搞错了????

在辛辛苦苦debug1小时后,我发现了出题人的险恶用心…

n=9999999967,大于1e9.两个数对n取模后最大可能到1e20.然后,我们的long long小朋友就光荣的炸掉了。。。

啊这,咋回事啊啥情况啊那咋整啊?long long小朋友你hold住啊!!!!!!!!!TAT

唉,向大佬请教吧,然后,笔者顶着大佬的最长的手指头,学到了解决方法。快速乘

快速乘实际上就是乘法,我们都知道,乘法的本质是加法,我们可以通过快速幂的思想比较轻松的写出快速乘的代码

#include<iostream>
#define ll long long
using namespace std;
const long long mod = 9999999967;

long long cheng(long long a, long long b) {
    long long res = 0;
    while (b)
    {
        if (b & 1) res = (res + a) % mod;
        b >>= 1;
        a = (a * 2) % mod;
    }
    return res;
}

long long ksm(long long a, long long b) {
    long long res = 1;
    while (b)
    {
        if (b & 1) res = cheng(res, a) % mod;
        b >>= 1;
        a = cheng(a, a) % mod;
    }
    return res;
}


int main()
{
    int t;
    cin >> t;
    while (t--) {
        long long ans;
        long long x, i;
        cin >> x >> i;
        ans = ksm(x, i);
        ans %= mod;
        cout << ans << endl;
    }
    return 0;
}

和快速幂一样,快速乘也需要通过位运算来实现,然后把快速乘的代码用在快速幂里面。

那么接下来,我们需要解释一下为什么这样就可以不用炸long long小朋友了。首先,两个1e10的数相乘取模mod,是先得到一个1e20的数字然后再取模,当然,在我们得到1e20的时候,long long就已经炸掉了。而如果我们通过位运算改乘为加,对两个1e10的数字相加后再对mod取模,数据的大小一定会在long long的1e18之内。而这一题就是因为出题人恶心的把取模的数字设置成10位,就是用来卡你的普通快速幂。如果不想到快速乘的话是很难写出来的(当然快速加不是唯一的解题方法,不过…那种方法似乎更加变态TAT,在这里提一下吧,想学的小伙伴去看看 [ __int128_t]数据结构)

作者:Avalon Demerzel,是个正在不断努力学习的小白,如果觉得博客不错,就来个三连吧(点个赞也行)。让我们一起进步。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值