题目描述
输入两个数 a, b,其中 b 极大。计算 a 的 b 次方对 1337 取模的结果。数据保证 a 在 int 范围内,b 小于 100 位。
输入描述
每个样例输入两行分别表示 a 和 b。
输出描述
每个样例输出一行表示:a 的 b 次方对 1337 取模的结果。
样例输入
2
3
样例输出
8
解析:由于题中的幂指数b不可避免的要使用高精度,本题的关键就在于如何简化对底数a的运算,以及寻求一种配合高精度型的指数的计算方法。
数学原理:牛顿二项展开式
对于任意底数a,都可以分成1337的整数倍数与a对1337取模之和,有如下表达式:
(以下公式均使用公式编辑器构建)
通过观察上式,我们可以得到一条重要性质
即ab对1337取模等价与kb对1337取模
我们不妨将此性质做一个推广
试想ax先乘上by再对1337取模
同样使用二项式,可以得到
其展开式中不含1337n的项只有k1x乘k2y
得出以上性质后,我们不难推出ab对1337取模等价与每次先对1337取模再乘a循环b次(请读者自证)☆⌒(>。≪)
第二步工作,构造出与高精度表示的指数b相性比较好的计算方法
考虑到高精度采用十进制表示,我们不妨以10为梯度进行划分。如下示例:
使用上文所述性质,有
将原问题分解为求k的指数的每一位次方对1337取模,这样便与高精度结合起来了ヾ(≧▽≦*)o
C
#include<stdio.h>
#include<string.h>
#define X 1337
#define N 100
int b[N]={0};
void str_to_int(char p[],int q[],int length){
//倒序转换
int i;
for(i=0;i<length;i++)
q[length-i-1]=p[i]-'0';
}
int compute(int a,int length,int carry,int end){
if(length>end)
return carry;
//二项展开式,a^b=(1337*n+k)^b
// = k^b + b*k^(b-1)*1337n^1 + …
int k,t,i;
k=a%X;
for(i=1;i<=b[length];i++)
carry=(carry*k)%X;
for(t=1,i=1;i<=10;i++)// k 放大到 k^10, 供下个循环使用
t=(t*k)%X;
return compute(t,length+1,carry,end);
}
int main()
{
int a,n;
char b1[N];
while(scanf("%d",&a)!=EOF){
getchar();
gets(b1);
str_to_int(b1,b,strlen(b1));
n=compute(a,0,1,strlen(b1)-1);
printf("%d\n",n);
}
return 0;
}