[BZOJ 4659] Lcm

BZOJ传送门

题目描述

给出A,B,考虑所有满足 l ≤ a ≤ A l\leq a\leq A laA l ≤ b ≤ B l\leq b\leq B lbB,且不存在 n > 1 n>1 n>1使得 n 2 n^2 n2同时整除 a a a b b b的有序数,对 ( a , b ) (a,b) (a,b),求其 l c m ( a , b ) lcm(a,b) lcm(a,b)之和。答案模 2 30 2^{30} 230

输入输出格式

输入格式

第一行一个整数T表示数据组数。接下来T行每行两个整数A,B表示一组数据。

T ≤ 2000 T ≤ 2000 T2000, A , B ≤ 4 × 1 0 6 A,B ≤ 4 × 10^6 A,B4×106

输出格式

对每组数据输出一行一个整数表示答案模 2 30 2^{30} 230的值

输入输出样例

输入样例#1
5
2 2
4 6
3 4
5 1
23333 33333
输出样例#1
7
148
48
15
451085813

解题分析

其实这道题不考虑那个因数没有平方数的条件的话和 **这道题**是一样的, 有这样一个式子:
∑ T = 1 n ( 1 + ⌊ n T ⌋ ) × ⌊ n T ⌋ 2 × ( 1 + ⌊ m T ⌋ ) × ⌊ m T ⌋ 2 T ∑ k ∣ T k × μ ( k ) \sum_{T=1}^{n}\frac{(1+\lfloor\frac{n}{T}\rfloor)\times\lfloor\frac{n}{T}\rfloor}{2}\times \frac{(1+\lfloor\frac{m}{T}\rfloor)\times\lfloor\frac{m}{T}\rfloor}{2} T\sum_{k|T}k\times \mu(k) T=1n2(1+Tn)×Tn×2(1+Tm)×TmTkTk×μ(k)
然后我们发现我们枚举的 T T T似乎就是 g c d ( i , j ) gcd(i,j) gcd(i,j)?? 于是 O ( N l n ( N ) ) O(Nln(N)) O(Nln(N))预处理, O ( T N ) O(T\sqrt N) O(TN )回答即可。

是否因数中含有完全平方数用 μ ( i ) \mu(i) μ(i)判定即可。

代码如下:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 4000500
const int MOD = 1 << 30;
#define ll long long
int miu[MX], pri[MX], pcnt, n, m, T;
ll F[MX];
bool npr[MX];
void get()
{
	miu[1] = 1;
	R int i, j, tar;
	for (i = 2; i < MX; ++i)
	{
		if(!npr[i]) pri[++pcnt] = i, miu[i] = -1;
		for (j = 1; j <= pcnt; ++j)
		{
			tar = i * pri[j];
			if(tar > MX) break;
			npr[tar] = true;
			if(!(i % pri[j])) break;
			miu[tar] = -miu[i];
		}
	}
	for (i = 1; i < MX; ++i) if(miu[i])
	{
		for (j = i; j < MX; j += i)
		(F[j] += miu[j / i] * j % MOD * (j / i) % MOD) %= MOD;
	}
	for (i = 1; i < MX; ++i) (F[i] += F[i - 1]) %= MOD;
}
IN int getsum(R int val) {return (val + 1) * val >> 1;}
int main(void)
{
	scanf("%d", &T);
	get();
	ll ans;
	W (T--)
	{
		scanf("%d%d", &n, &m);
		if(n > m) std::swap(n, m); ans = 0;
		for (R int lef = 1, rig; lef <= n; lef = rig + 1)
		{
			rig = std::min(n / (n / lef), m / (m / lef));
			(ans += (F[rig] - F[lef - 1]) * getsum(n / lef) % MOD * getsum(m / lef) % MOD) %= MOD;
		}
		printf("%lld\n", (ans % MOD + MOD) % MOD);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值