测试(快速幂+数学+前缀和)
洛谷 P1630 求和
给一个式子,求它的值,(1^b+2^b+...+a^b)%1e4
输入格式
第一行一个数t,表示有t组测试数据
对于每组测试数据,一行有两个整数a,b
部分数据:1<=t<=10, a,b<=1e3
对于100%的数据,1<=t<=100,1<=a,b<=1e9
输出格式
共t行,每行一个整数
输入/输出例子1
输入:
1
2 3
输出:
9
样例解释
无
解释一:取模的值通常是有规律的,模范围非常小可以通过找规律来解决
解释二(通用+推荐看看):
枚举范围大的时候,考虑两个思路,1分类,2规律(周期性)
求规律可以用打表或者用数学,打表的话注意题中特殊的数据范围,并且缩小范围
解释一:
指数很大我们可以用快速幂来解决,再逆天的数都可以在64次内解决(即O(1))。
所以b很大不是问题(逃),问题是a这么大如何解决,这样一个循环肯定是要爆的。
取模的值通常是有规律的,而且这道题给的模范围非常小,也就是说可以通过找规律来解决
原式:a^b % p
即:b个a相乘再模上p,下面用2个a来代替b个a
转换:
(a*a) % p 通过乘法取模分配律得到下面的式子
(a%p * a%p)%p (也就是b个a%p相乘再模p)
(a%p)^b % p
也就是a的范围被p限制住了,若p=100,那么a=101 相当于 a=1
所以这道题写一个前缀和就做出来了
解释二:
可以注意题中模数1e4这个,范围肯定有提示。
考虑分类,每个数分类,比如2的倍数,3的倍数,但是太麻烦了,且不好实现,先放着,暂不考虑
考虑规律,我们可以把模数的1e4缩小到3
引入一个知识,同余
((a+b)^x ) %b = ( a^x)%b
根据二项式,((a+b))^x暂开可得,C(x,0)*a^0*b^x + C(x,1)*a^1*b^(x-1) + ..... + C(x, x)*a^x*b^0
[ 此段每个项都是xxx*b,那么%b一定是b的倍数 ] [ 最后这一段没有b]
所以整个式子%b= a^x
然后找规律
1^b+2^b+3^b+.....+a^b
转换一下为
(1+3)^b+(2+3)^b+(3+3)^b+(1+3)^b+(2+3)^b+(3+3)^b+.....+a^b
再次转换为
1^b+2^b+3^b+1^b+2^b+3^b+.....+a^b
发现了规律,超过模数后,出现周期,周期次数为a/3,周期剩下的数为a%3,周期的和可以记录一下(前缀和),根据这一点推广到一般,得到此题的解
#include <bits/stdc++.h> #define int long long using namespace std; const int N=1e4+5, Mod=1e4; int t, a, b, sum[N]; int Pow(int a, int b) { if (b==1) return a%Mod; int t=Pow(a, b/2); if (b%2==0) return (t%Mod*t%Mod)%Mod; else return (t%Mod*t%Mod*a%Mod)%Mod; } signed main() { scanf("%lld", &t); while (t--) { scanf("%lld%lld", &a, &b); for (int i=1; i<=10000; i++) sum[i]=(sum[i-1]+Pow(i, b))%Mod; printf("%lld\n", (a/10000*sum[10000]%Mod+sum[a%10000]%Mod)%Mod); } return 0; }