这类问题的相同之处在于,数的大小超出了原生数据类型所能表示的范围。如果用Python或者Java,就不必再看下去了。。。。。。
1. 大数的模幂运算
给定x和y,求x的y次幂模k的余数
unsigned int quick_power_mod(unsigned int x, unsigned int y, unsigned int k)
{
unsigned int res = 1;
x %= k;
while(y != 0)
{
if(y & 1)
{
res = (res * x) % k;
}
y >>= 1;
x = (x * x) % k;
}
return res;
}
这种做法的道理如下,指数y的二进制表示为:
y=a0⋅20+a1⋅21+a2⋅22+⋯+an⋅2n,ai∈{0,1}
那么
xy=xa0⋅20+a1⋅21+a2⋅22+⋯+an⋅2n=xa0⋅20⋅xa1⋅21⋅xa2⋅22⋅⋯⋅xan⋅2n,ai∈{0,1}
又因为模运算有如下性质
(a⋅b)modc=((amodc)(bmodc))modc
于是我们有
xymodk=((xa0⋅20modk)⋅(xa1⋅21modk)⋅(xa2⋅22modk)⋅⋯⋅(xan⋅2nmodk))modk,ai∈{0,1}
该算法即在按照上式从左到右一项一项的计算。体现为,遍历y的每一个二进制位,如果该位为1,将当前的计算结果乘以当前x的值并求余,如果该位为0,则不乘或者说乘以1;每遍历y的一位,将x做一次平方,对应着上式中依次乘2的x的指数。
2. 大数的进制转换
给定a进制的数x(字符串形式),转换为b进制的数y
unsigned int convert_base(std::vector<unsigned int> &from_num, std::vector<unsigned int> &to_num, unsigned int from_base, unsigned int to_base)
{
for(int i = 0; i < from_num.size(); )
{
int carry = 0;
for(int j = i; j < from_num.size(); j++)
{
int tmp = (from_num[j] + carry * from_base) % to_base;
from_num[j] = (from_num[j] + carry * from_base) / to_base;
carry = tmp;
}
to_num.push_back(carry);
while(from_num[i] == 0)
{
i++;
}
}
}
此处使用的是除k取余法,输入的vector也被改变了,用来存储每步计算的商。