GMOJ 4161 / Luogu P4449 于神之怒 (加强版) 题解

3 篇文章 0 订阅

于神之怒 (加强版) 题解

Description

F ( n , m ) = ∑ i = 1 n ∑ j = 1 m gcd ⁡ ( i , j ) k F(n,m)=\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^k F(n,m)=i=1nj=1mgcd(i,j)k

Solution

莫反套路
F ( n , m ) = ∑ i = 1 n ∑ j = 1 m gcd ⁡ ( i , j ) k = ∑ d = 1 n d k ∑ l = 1 ⌊ n d ⌋ μ ( l ) ⌊ n d l ⌋ ⌊ m d l ⌋ F(n,m)=\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^k=\sum_{d=1}^nd^k\sum_{l=1}^{\lfloor\frac{n}{d}\rfloor}\mu(l)\lfloor\frac{n}{dl}\rfloor\lfloor\frac{m}{dl}\rfloor F(n,m)=i=1nj=1mgcd(i,j)k=d=1ndkl=1dnμ(l)dlndlm
T = d l T=dl T=dl
F ( n , m ) = ∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ d ∣ T d k μ ( T d ) F(n,m)=\sum_{T=1}^n\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}d^k\mu(\frac{T}{d}) F(n,m)=T=1nTnTmdTdkμ(dT)
前面可以数论分块 O ( n ) O(\sqrt{n}) O(n )求,考虑 ∑ d ∣ T d k μ ( T d ) \sum_{d|T}d^k\mu(\frac{T}{d}) dTdkμ(dT)
f ( n ) = ∑ d ∣ n d k μ ( n d ) , p o w ( n ) = n k f(n)=\sum_{d|n}d^k\mu(\frac{n}{d}),pow(n)=n^k f(n)=dndkμ(dn),pow(n)=nk
f = p o w ∗ μ f=pow*\mu f=powμ
所以 f f f为积性函数,线性筛即可.
复杂度 O ( n log ⁡ ( n ) + t n ) O(n\log(n)+t\sqrt{n}) O(nlog(n)+tn )

Code

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
const LL MOD = 1e9 + 7;
int T, k, vis[5000010], cnt, F[5000100], p[5000010], mu[5000010], ans;
LL f[5000010], n, m;
inline int read() {
	int res = 0; char ch = getchar();
	for(; ch > '9' || ch < '0'; ch = getchar());
	for(; ch >= '0' && ch <= '9'; res = res * 10 + ch - '0', ch = getchar());
	return res;
}
int Qpower(LL x, LL k) {
	LL res = 1;
	while(k) {
		if(k & 1) res = res * x % MOD;
		x = x * x % MOD;
		k >>= 1;
	}
	return res;
}
int main() {
	T = read(), k = read();
	mu[1] = 1, vis[1] = 1, f[1] = 1;
	for(int i = 2; i <= 5e6; ++i) {
		if(!vis[i]) p[++cnt] = i, mu[i] = -1, f[i] = Qpower(i, k) - 1;
		for(int j = 1; j <= cnt && p[j] * i <= 5e6; ++j) {
			vis[i * p[j]] = 1;
			if(i % p[j] == 0) {
				f[i * p[j]] = f[i] * Qpower(p[j], k) % MOD;
				break;
			}
			mu[i * p[j]] = - mu[i];
			f[i * p[j]] = f[i] * f[p[j]] % MOD;
		}
	}
	for(int i = 1; i <= 5e6; ++i)
		F[i] = (F[i - 1] + f[i]) % MOD;
	while(T--) {
		ans = 0;
		n = read(), m = read();
		if(n > m) swap(n, m);
		for(int l = 1, r; l <= n; l = r + 1) {
			r = min(n / (n / l), m / (m / l));
			ans = (ans + ((n / l) * (m / l)) % MOD * (F[r] - F[l - 1] + MOD) % MOD) % MOD;
		}
		printf("%lld\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值