[湖北省队互测2014]一个人的数论

\(n\) 的唯一分解,求 \([1,n]\) 中与 \(n\) 互质的数的 \(k\) 次方和。

先考虑莫反:

\[\sum_{i=1}^n [gcd(i,n)==1]i^k \]

\[\sum_{i=1}^n i^k \sum_{d|gcd(i,n) \mu(d)} \]

\[\sum_{d|n} \mu(d)\sum_{d|i} i^k \]

\[\sum_{d|n} d^k\mu(d)\sum_{i=1}^{n\over d} i^k \]

到此可以获得40分的好成绩。

发现后面是个多项式,我们可以拉插/消元/伯努利数搞出系数,设:

\[f(x)=\sum_{i=1}^x i^k=\sum_{i=0}^{k+1} a_ix^i \]

那么原来的式子可以变成:

\[\sum_{d|n} d^k \mu(d)\sum_{i=0}^{k+1} a_i({n\over d})^i \]

\[\sum_{i=0}^{k+1}a_i \sum_{d|n} \mu(d)d^k({n\over d})^i \]

后面那一坨实际上是一个关于 \(n\) 的积性函数(积性函数的狄利克雷卷积还是积性函数),我们只用考虑 \(n=p^t\) 的情况,而 \(n\) 的唯一分解一开始就给出,直接乘起来就可以。

先把 \(n=p^t\) 代入式子

\[\sum_{d|p^t} \mu(d)d^k({p^t\over d})^i \]

\[\sum_{j=0}^t \mu(p^j)p^{jk+i(t-j)} \]

注意到当 \(j>=2\) 时,\(\mu(p^j)=0\),对答案没有贡献,所以上式等于

\[p^{it}-p^{k+i(t-1)} \]

于是就写完了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 2e3 + 5, M = 205, mod = 1e9 + 7;

#define int long long

int p[N], a[N], d[N], g[M][M], f[M], w, k;

inline int power(int a, int b) {
	int t = 1, y = a, k = b;
	while (k) {
		if (k & 1) t = (1ll * t * y) % mod;
		y = (1ll * y * y) % mod; k >>= 1;
	} return t;
}

inline void getf() {
	for (int i = 1; i <= k + 3; ++i) {
		g[i][1] = 1; //cout << 1 << ' ';
		for (int j = 2; j <= k + 3; ++j)
			g[i][j] = (1ll * g[i][j - 1] * i) % mod;//, cout << g[i][j] << ' ';
		g[i][k + 4] = (g[i - 1][k + 4] + power(i, k));// cout << g[i][k + 4] << endl;
		if (g[i][k + 4] >= mod) g[i][k + 4] -= mod;
	}
	for (int i = 1; i <= k + 3; ++i) {
		int p = i;
		for (int j = i; j <= k + 3; ++j)
			if (g[j][i] == g[p][i]) p = i;
		for (int j = 1; j <= k + 4; ++j) swap(g[i][j], g[p][j]);
		for (int j = i + 1; j <= k + 4; ++j) g[i][j] = (1ll * g[i][j] * power(g[i][i], mod - 2)) % mod;
		for (int j = 1; j <= k + 3; ++j)
			if (i != j)
				for (int l = i + 1; l <= k + 4; ++l)
					g[j][l] = ((g[j][l] - (1ll * g[j][i] * g[i][l] % mod)) % mod + mod) % mod;			
	} for (int i = 1; i <= k + 3; ++i) f[i] = g[i][k + 4];
}

signed main() {
	scanf("%lld%lld", &k, &w);
	getf(); int ans = 0; int del;
	for (int i = 1; i <= w; ++i)
		scanf("%lld%lld", &p[i], &a[i]);
	for (int i = 0; i < k + 3; ++i) {
		del = 1; int num;
		for (int j = 1; j <= w; ++j) {
			num = power(p[j], (1ll * i * a[j]) % (mod - 1)) - power(p[j], k + (1ll * (a[j] - 1) * i) % (mod - 1)) % mod;
			del = (1ll * del * num) % mod;
		}
		del = (1ll * del * f[i + 1]) % mod; 
		ans = (ans + del) % mod;
		if (ans < 0) ans += mod;
	} printf("%lld", ans);
	return 0;
}
posted @ 2021-04-09 21:32  Smallbasic  阅读(65)  评论(0)    收藏  举报