题目
给定正整数 n,求 (18+28+…+n8) mod 123456789。其中 mod 表示取余。
输入
输入的第一行包含一个整数 。
输出
输出一行,包含一个整数,表示答案。
样例输入
2
样例输出
257
提示
对于 20% 的评测用例,1 ≤ n ≤ 20 。
对于 60% 的评测用例,1 ≤ n ≤ 1000 。
对于所有评测用例,1 ≤ n ≤ 1000000 。
解题思路
由题目可知,本题的数据范围可能很大,因此需要设置为int类型,其次,尽可能多次取余,让更小的余数相乘,而不是让大数相乘。
难点
- 取余具有加法、乘法的分配、交换律,如下:
(A+B)%C = (A%C+B%C)%C
(A*B)%C = ((A%C)*(B%C))%C
; - 赋值符号的右边,如果是A*B的形式,那么A会“暂存”结果,再赋值给等号左边,这一理解关系到A的取值范围的设定(比如,i 应当设定为long int类型);
- 做题过程中错误分析,试图一步到位计算4次、8次:
temp = i*i%M;
a+=((temp*temp)%M*(temp*temp)%M)%M;
看似上述代码和正确代码中的如下部分一致,但是上述代码实际是将“4次取模先乘以4次,再取模(即先算(temptemp)%M(temp*temp),会越界)”,下部分代码是“先获得4次取模,再以‘4次取模’相乘获得8次的值”:
temp = i*i%M;
temp = (temp*temp)%M;
temp = (temp*temp)%M;
以上三行代码也等价于(和错误代码相差表优先顺序的括号):
temp = i*i%M;
temp = ((temp*temp)%M)*((temp*temp)%M)%M;
代码
#include<stdio.h>
#define M 123456789
int main()
{
int n;
long int i,temp;
long int a=1;
scanf("%d",&n);
for (i=2;i<=n;i++)
{
temp = i*i%M;
temp = (temp*temp)%M;
temp = (temp*temp)%M;
a+=temp;
a%=M;
}
printf("%ld",a);
return 0;
}