Project-Euler-048

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

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

猜你喜欢

转载自blog.csdn.net/Ivan_zcy/article/details/83068555