位运算_递推_CH0102_64位整数乘法

版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/83210436

点此进入题目页面

思路分析:给出两种方法, 法1基于递推, 法2利用C++基本数据类型的性质

法1:

考虑b的二进制表示, (a * b) mod p = (a * (c_{k}2^{k} +...+ c_{0}2^{0})) mod p = (c_{k}a2^{k}+...+c_{0}a2^{0}) mod p

又: a2^{i} = 2 * a2^{i - 1} (i >= 1), 则可先求出s = a2^{i - 1} mod\: p, 且s < p <= 10^{18}, 可直接使用语句: s * 2 % p 计算a2^{i}\: mod\: p

至此,首先计算a2^{0}\: mod\: p, 然后递推即可, AC代码如下:

//CH0102_64位整数乘法
#include <iostream>
#include <cstdio>
using namespace std;
//返回(a * b) mod p的值, 要求:1 <= a, b, p <= 10^18
long long getVal(long long a, long long b, long long p){
	long long ans = 0, tmp = a % p;
	for(; b; b >>= 1, tmp = tmp * 2 % p) if(b & 1) ans = (ans + tmp) % p;
	return ans;	
} 
int main(){
	long long a, b, p;
	scanf("%lld %lld %lld", &a, &b, &p);
	cout << getVal(a, b, p) << endl;
	return 0;
}

法2:

由 (a * b) mod p = a * b - \left \lfloor \frac{a * b}{p} \right \rfloor * p,  且该等式两端的值小于2^{64}, 可先计算s = \left \lfloor \frac{a * b}{p} \right \rfloor的值, 如何计算s? 考虑到s <= 10^{18}, 利用C++中long double的有效数字为18~19位, 因此对a, b, p使用long double计算a * b / p的值, 对结果取整数部分即为s的值.继而将a, b, s, p均定义为unsigned long long 类型, 依据C++中unsigned long long运算性质, 表达式a * b - s * p的值为其数学上的实际值对2^{64}取模, 因为其实际值小于2^{64}, 故表达式a * b - s * p 为其实际值, 具体步骤如下AC代码所示:

//CH0102_64位整数乘法
#include <iostream>
#include <cstdio>
using namespace std;
typedef unsigned long long ull; 
//返回(a * b) mod p的值, 要求:1 <= a, b, p <= 10^18
ull getVal(ull a, ull b, ull p){
	return a * b - (ull)((long double)a * b / p) * p;
} 
int main(){
	long long a, b, p;
	scanf("%lld %lld %lld", &a, &b, &p);
	cout << getVal(a, b, p);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/solider98/article/details/83210436
今日推荐