很久之前存的古代经典题,思路是 cyj 的。
感谢那时候先辈们的分享精神,这就是十年前的 OI 圈子吗。
思路
莫比乌斯反演。
首先注意到一个自然数幂次和,令 \(F(n) = \sum\limits_{i = 1}^n i^k\),有经典结论是 \(F(n)\) 是关于 \(n\) 的 \(k + 1\) 次多项式。
尝试用类似的结构表示答案:令 \(G(n) = \sum\limits_{i = 1} i^k [\gcd(i, n) = 1]\).
考虑到 \(F(n), G(n)\) 之间的相似性,这里不采用 \(\mu\) 反演将 \(G(n)\) 化简,而是考虑应用莫比乌斯反演。
考虑 \(n\) 的每个质因子作为 \(\gcd\) 时的贡献,注意到 \(F(n) = \sum\limits_{d \mid n} d^k F(\frac{n}{d})\).
对其应用莫比乌斯反演得 \(G(n) = \sum\limits_{d \mid n} \mu(d) d^k F(\frac{n}{d})\).
将 \(F(\frac{n}{d})\) 展开成多项式形式:\(G(n) = \sum\limits_{d \mid n} \mu(d) d^k \sum\limits_{i = 0}^{k + 1} f_i (\frac{n}{d})^i\).
整理得 \(G(n) = \sum\limits_{i = 0}^{k + 1} f_i n^i \sum\limits_{d \mid n} \mu(d) d^{k - i}\).
因为 \(\mu(d) d^{k - i}\) 是积性函数,并且题目提醒我们 \(n\) 可以分解成唯一分解形式。
因此可以考虑把后面的部分看成是每个质因子的贡献之并,这样每个质因子单独的贡献或许是容易求的。
一般而言对于含有 \(\mu\) 的高次项,因为 \(\mu(x^2) = 0\),所以都会获得次数至多为 \(1\) 的限制。
所以有 \(G(n) = \sum\limits_{i = 0}^{k + 1} f_i n^i \prod\limits_{p_j \mid n} \sum\limits_{t = 0}^{a_j} \mu(p_j^t) p_j^{t (k - i)}\).
因为 \(t \geq 2\) 时 \(\mu = 0\),所以只需要考虑 \(t \leq 1\) 时的贡献。
于是有 \(G(n) = \sum\limits_{i = 0}^{k + 1} f_i n^i \prod\limits_{p_j \mid n} (1 - p_j^{k - i})\).
于是现在我们只需要获得关于自然数幂和的多项式就可以解决问题了。
根据上文只需要随意拉插带走,跑得飞快。
代码
#include <cstdio>
using namespace std;
#define il inline
const int maxn = 1e3 + 5;
const int mod = 1e9 + 7;
il int cmod(int x) { return (x >= mod ? x - mod : x); }
il void add(int &x, int y) { x += y, x -= (x >= mod ? mod : 0); }
il int qpow(int base, int power = mod - 2)
{
int res = 1;
while (power)
{
if (power & 1) res = 1ll * res * base % mod;
base = 1ll * base * base % mod, power >>= 1;
}
return res;
}
int n, k, len;
int A[maxn], f[maxn], p[maxn], al[maxn];
il void poly_mul(int a, int b)
{
len++;
for (int i = len; i >= 1; i--) A[i] = (1ll * A[i] * b + 1ll * A[i - 1] * a) % mod;
A[0] = 1ll * A[0] * b % mod;
}
il void num_mul(int v) { for (int i = 0; i <= len; i++) A[i] = 1ll * A[i] * v % mod; }
il void poly_add()
{
for (int i = 0; i <= len; i++) add(f[i], A[i]), A[i] = 0;
A[len = 0] = 1;
}
il void init(int &k)
{
A[0] = 1, len = 0;
int sum = 0;
for (int i = 1; i <= k + 3; i++)
{
add(sum, qpow(i, k));
int mul = qpow(sum);
for (int j = 1; j <= k + 3; j++)
{
if (i == j) continue;
poly_mul(1, mod - j);
mul = 1ll * mul * (i + mod - j) % mod;
}
num_mul(qpow(mul)), poly_add();
}
}
int main()
{
scanf("%d%d", &k, &n);
int N = 1;
for (int i = 1; i <= n; i++) scanf("%d%d", &p[i], &al[i]), N = 1ll * N * qpow(p[i], al[i]) % mod;
init(k);
int res = 0, pw = N;
for (int i = 1; i <= k + 3; i++)
{
int ans = 1ll * pw * f[i] % mod;
pw = 1ll * pw * N % mod;
for (int j = 1; j <= n; j++) ans = 1ll * ans * (1 + mod - qpow(p[j], k - i + mod - 1)) % mod;
add(res, ans);
}
printf("%d\n", res);
return 0;
}
标签:队互测,limits,int,题解,sum,mu,P6271,il,mod
From: https://www.cnblogs.com/lingspace/p/p6271.html