HDU 4746-Mophues (莫比乌斯反演)

本文介绍了一种算法问题的解决思路,该问题涉及质因数计数与莫比乌斯反演的应用。文章首先定义了一个概念——幸运数,并通过使用前缀和与莫比乌斯反演技术来高效地解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:定义x,p:假如x的所有质因数的个数小于等于p,则称x is a lucky number of P.然后问你1<=x<=n 

1<=y<=m中,有多少对(x,y)满足gcd(x,y)is a lucky number of P.题意:定义x,p:假如x的所有质因数的个数小于等于p,则称x

题解:这道题和之前做的gcd很像,我们可以定义一个函数F(x)表示x有多少个质因数,假设我们当前求gcd(x,y)=d,可以等价于求gcd(x,y)=1 1<=x<=n/d && 1<=y<=m/d...这在之前的题目中已经说明过了,我们仍然可以仿照之前的做法,令f(d)为gcd(x,y)=d的对数,g(d)为gcd(x,y)=d的倍数的个数。显而易见,g(d)可以无脑算出,答案是g(d)=[n/d][m/d]([]为向下取整),然后我们可以利用莫比乌斯反演定理,在O(n)的时间内求出每个值的贡献,然而对于这道题来说是超时的,因此,我们仍然考虑分块,这道题并不想之前呢样简单的求一波前缀和就可以的。

因为涉及到素因数的个数,故要开一个二维的前缀和dp[d][p]:表示质因数个数<=p时对g(d)的贡献系数。

#include<map>     
#include<stack>            
#include<queue>            
#include<vector>    
#include<string>  
#include<math.h>            
#include<stdio.h>            
#include<iostream>            
#include<string.h>            
#include<stdlib.h>    
#include<algorithm>   
#include<functional>    
using namespace std;
typedef long long  ll;
#define inf  1000000000       
#define mod 1000000007             
#define maxn  560050  
#define lowbit(x) (x&-x)            
#define eps 1e-9  
ll a[maxn] = { 1,1 }, b[maxn], mu[maxn], cnt, num[maxn], dp[maxn][20];
void init()
{
	ll i, j;mu[1] = 1;
	for (i = 2;i<maxn;i++)
	{
		if (a[i] == 0)
			b[++cnt] = i, mu[i] = -1, num[i] = 1;
		for (j = 1;j <= cnt && i*b[j] <= maxn;j++)
		{
			a[b[j] * i] = 1; 
			num[b[j] * i] = num[i] + 1;
			if (i%b[j] == 0)
			{
				mu[b[j] * i] = 0;
				break;
			}
			else
				mu[b[j] * i] = -mu[i];
		}
	}
	for (i = 1;i <= maxn;i++)
		for (j = i;j <= maxn;j += i)
			dp[j][num[i]] += mu[j / i];
	for (i = 0;i <= maxn;i++)
		for (j = 1;j <= 19;j++)
			dp[i][j] += dp[i][j - 1];
	for (i = 1;i <= maxn;i++)
		for (j = 0;j <= 19;j++)
			dp[i][j] += dp[i - 1][j];
}
int  main(void)
{
	init();
	ll T, i, x, y, k, p, last;
	scanf("%lld", &T);
	while (T--)
	{
		ll sum = 0;
		scanf("%lld%lld%lld", &x, &y, &p);
		if (x > y)  swap(x, y);p = min(p, 18ll);
		for (i = 1, last = 0;i <= x;i = last + 1)
		{
			last = min(x / (x / i), y / (y / i));
			sum += (ll)(dp[last][p] - dp[i-1][p])*(x / i)*(y / i);
		}
		printf("%lld\n", sum);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值