于神之怒加强版 简要题解

这道题的式子可以硬推, 也可以按 \(f(gcd(i,j)) = (1*g) (gcd(i,j))\) 的套路来快速得出答案(其实总行数没少几行qwq), 不细说。

最后要算的就是:

\[\sum_{T=1}^{min(n,m)} \lfloor \frac{n}T \rfloor \lfloor \frac{m}T \rfloor \sum_{d|T} d^k \mu(\frac{T}d) \]

如果去掉\(\mu(\frac{T}d)\), 那么我将绝杀, 但是去不得

所以怎么预处理\(\sum_{d|T} d^k \mu(\frac{T}d)\)

我的方法是把它拆成 \(id_k * \mu\), 就可以 \(O(T \log \log T)\) 搞, 可以过。(\(id_k\) 是完全积性函数,可以线性筛出来, 复杂度大约有 \(O(n + prime\_cnt \log k)\)

神仙们的线性筛以后会补qwq

Luogu数据AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e6 + 15;
const int mod = 1000000007;
#define li long long
li ksm(li a, li b, li p) {
	li res = 1ll;
	for(;b;b>>=1, a=(a*a)%p)
		if(b&1) res = (res*a)%p;
	return res%p;
}

int t; li k;
int pr_cnt, prime[maxn], v[maxn];
li idk[maxn], g[maxn];
void euler(int n) {
	idk[1] = 1ll;
	for(int i=2; i<=n; ++i) {
		if(!v[i]) {
			v[prime[++pr_cnt] = i] = i;
			idk[i] = ksm(i, k, mod);
		}
		for(int j=1; j<=pr_cnt; ++j) {
			if(prime[j] > n/i || prime[j] > v[i]) break;
			v[prime[j] * i] = prime[j];
			idk[prime[j] * i] = idk[i] * idk[prime[j]] % mod;
		}
	}
	for(int i=1; i<=n; ++i) g[i] = idk[i];
	for(int i=1; i<=pr_cnt; ++i)
		for(int j=n/prime[i]; j>0; --j) {
			g[prime[i] * j] -= g[j];
			g[prime[i] * j] = (g[prime[i] * j]%mod+mod)%mod;
		}
	for(int i=2; i<=n; ++i) {
		g[i] += g[i-1];
		g[i] = (g[i]%mod+mod)%mod;
	}
}

int main()
{
	cin >> t >> k;
	euler(5000000);
	while(t--) {
		int n, m; scanf("%d%d", &n,&m);
		int len = min(n,m);
		li ans = 0ll;
		for(int i=1,j; i<=len; i=j+1) {
			j = min(n/(n/i), m/(m/i));
			j = min(j, len);
			ans += (g[j]-g[i-1]) * (n/i) % mod * (m/i) % mod;
			ans = (ans%mod+mod)%mod;
		}
		cout << ans << '\n';
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/tztqwq/p/12765057.html
今日推荐