【洛谷P1630】求和

Description

【LuoguP1630】求和

给定$a,b$,求$(\sum\limits_{i=1}^{a}{i^b})\mod 10000$

多组询问,$a,b\le 1e9$

Solution

前缀和+快速幂

如果暴力计算答案,那么时间复杂度为$O(Tab)$

使用快速幂优化,那么时间复杂度为$O(Ta\log b)$

考虑这样一个式子:$$i^b\mod n=(i\mod n)^b$$

那么我们就可以预处理出$i^b,i\in[0,9999]$的值,那么时间复杂度变成了$O(Ta)$

考虑每个$i^b\mod 10000$的值,发现整个序列就是$i^b,i\in[0,9999]$重复了$\lfloor\frac{a}{10000}\rfloor$次,再加上最后剩下的$i^b,i\in[0,9999]$的前$a\mod 10000$个数

那么我们就可以处理出$i^b\mod 10000$的前缀和,然后在预处理完成之后$O(1)$即可完成

这样时间复杂度就变成了$O(T\times 10000\times \log b)$

Code

#include <bits/stdc++.h>
// check if it is judged online

namespace shl {
    typedef long long ll;
    inline ll read() {
        ll ret = 0, op = 1;
        char c = getchar();
        while (!isdigit(c)) {
            if (c == '-') op = -1;
            c = getchar();
        }
        while (isdigit(c)) {
            ret = ret * 10 + c - '0';
            c = getchar();
        }
        return ret * op;
    }
    int T;
    int a, b;
    ll c[10010], sum[10010];
    const int mod = 1e4;
    ll qpow(ll x, ll y) {
        ll ret = 1;
        while (y) {
            if (y & 1) ret = (ret * x) % mod;
            x = x * x % mod;
            y >>= 1;
        }
        return ret;
    }
    int main() {
        T = read();
        while (T--) {
            a = read(), b = read();
            for (register int i = 0; i < 10000; ++i) {
                c[i] = qpow(i, b);
                if (i == 0) sum[i] = c[i];
                else sum[i] = sum[i - 1] + c[i];
            }
            printf("%lld\n", ((sum[mod - 1] * (a / mod) % mod) + sum[a % mod]) % mod);
        }
        return 0;
    }
}
int main() {
#ifdef LOCAL
    freopen("textname.in", "r", stdin);
    freopen("textname.out", "w", stdout);
#endif
    shl::main();
    return 0;
}

 

posted @ 2019-09-23 19:44  AD_shl  阅读(248)  评论(0编辑  收藏  举报