048题:
题意:
十项的自幂级数求和为 1^1 + 2^2 + 3^3 + … + 10^10 = 10405071317。
求如下一千项的自幂级数求和的最后10位数字:1^1 + 2^2 + 3^3 + … + 1000^1000
思路:
设mod为1e10,根据同余定理,我们可以利用快速幂求i^i关于mod的模。但是有一个问题,就是快速幂中存在两数先相乘再取余mod的过程,可能两数在相乘时就爆long long了。因此,我们可以通过一个小技巧来防治爆long long。
对于a * b % mod,我们设k为1e5,那么一定存在a = ik + j,b = pk + q (其中i = a / k,j = a % k,p = b / k,q = b % k)
把a和b带入原式,得到:
a * b % mod = (ik + j) * (pk + q) % mod
= (ipk^2 + iqk + jpk + jq) % mod
由于ipk^2,iqk,jpk,jq都在longlong范围内,因此解决了爆longlong问题
代码:
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#define d int32_t
#define r return
#define ll int64_t
#define t (ll)1e5
#define mod (ll)1e10
#define For(i, star, endd) for(d i = star; i <= endd; i++)
//乘法防爆longlong
ll mul (ll a, ll b) {
ll ans = 0;
ll i = a / t;
ll j = a % t;
ll p = b / t;
ll q = b % t;
ans = (i * p % mod * t % mod *t % mod + i * q % mod * t % mod + j * p % mod * t % mod + j * q % mod) % mod;
r ans;
}
//快速幂
ll quick(ll a, ll b) {
ll ans = 1;
while (b) {
if (b & 1) ans = mul(ans, a);
b >>= 1;
a = mul(a, a);
}
r ans;
}
//循环球i^i
ll work() {
ll ans = 0;
For(i, 1, 1000) {
ans = (ans + quick(i, i)) % mod;
}
r ans;
}
d main()
{
ll ans = work();
printf("%" PRId64 "\n", ans);
r 0;
}
最后结果为:9110846700
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢