题解 「BZOJ2137」submultiple
阅读原文时间:2023年07月08日阅读:3

题目传送门

题目大意

给出 \(M,k\) ,求出

\[\sum_{x|M}\sigma(x)^k
\]

给出 \(P_i\),满足 \(n=\prod_{i=1}^{n}a_i^{P_i}\),其中 \(a_i\) 是第 \(i\) 个质数。

对于 \(45\%\) 的数据点满足 \(k\le 10^5\),对于其余数据点满足 \(k\le 12\) 。

思路

首先你发现答案就是:

\[\prod_{i=1}^{n}(\sum_{j=1}^{P_i+1}j^k)
\]

(因为约数个数是个积性函数)

然后你发现对于 \(45\%\) 的数据点可以直接暴力,然后另外一部分可以直接拉格朗日插值法解决。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define mod 1000000007
#define int long long
#define MAXN 100005

int n,k,P,pre[MAXN];

int qkpow (int a,int b){
    int res = 1;for (;b;b >>= 1,a = a * a % mod) if (b & 1) res = res * a % mod;
    return res;
}
int inv (int x){return qkpow (x,mod - 2);}

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int Sum (int x){//计算\sum_{i=1}^{x}i^k
    if (x <= k + 1) return pre[x];
    int ans = 0;
    for (Int i = 0;i <= k + 1;++ i){
        int mot = 1,son = 1;
        for (Int j = 0;j <= k + 1;++ j)
            if (i != j) mot = mot * (i + mod - j) % mod,son = son * (x + mod - j) % mod;
        ans = (ans + pre[i] * son % mod * inv (mot) % mod) % mod;
        ans = (ans % mod + mod) % mod;
    }
    return ans;
}

signed main(){
    read (n,k),k %= (mod - 1);
    if (k <= 12){//使用拉格朗日插值
        pre[0] = qkpow (0,k);
        for (Int i = 1;i <= k + 1;++ i) pre[i] = (pre[i - 1] + qkpow (i,k)) % mod;
        int res = 1;for (Int i = 1;i <= n;++ i) read (P),P %= mod,res = res * Sum (P + 1) % mod;
        write (res),putchar ('\n');
        return 0;
    }
    int ans = 1;
    pre[0] = qkpow (0,k);for (Int i = 1;i <= MAXN - 4;++ i) pre[i] = (pre[i - 1] + qkpow (i,k)) % mod;
    for (Int i = 1;i <= n;++ i) read (P),P %= mod,ans = 1ll * ans * pre[P + 1] % mod;
    write (ans),putchar ('\n');
    return 0;
}