浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

HDU4746 Mophues

题目地址

题目链接

Description

 As we know, any positive integer C ( C >= 2 ) can be written as the multiply of some prime numbers:
    C = p1×p2× p3× ... × pk
which p1, p2 ... pk are all prime numbers.For example, if C = 24, then:
    24 = 2 × 2 × 2 × 3
    here, p1 = p2 = p3 = 2, p4 = 3, k = 4

Given two integers P and C. if k<=P( k is the number of C's prime factors), we call C a lucky number of P.

Now, XXX needs to count the number of pairs (a, b), which 1<=a<=n , 1<=b<=m, and gcd(a,b) is a lucky number of a given P ( "gcd" means "greatest common divisor").

Please note that we define 1 as lucky number of any non-negative integers because 1 has no prime factor. 

Input

The first line of input is an integer Q meaning that there are Q test cases.
Then Q lines follow, each line is a test case and each test case contains three non-negative numbers: n, m and P (n, m, P <= 5×10 5. Q <=5000).

Output

For each test case, print the number of pairs (a, b), which 1<=a<=n , 1<=b<=m, and gcd(a,b) is a lucky number of P.

Sample Input

2
10 10 0
10 10 1

Sample Output

63
93

Solution

神仙结论。不过其实不难想。。。但是我不看题解很难想到。
首先大力推式子但是我懒得写推导在这里了意会一下吧,写到这道题应该也不难推到这里=_=

\[\sum_{T=1}^n\frac{n}{T}\frac{m}{T}\sum_{d|T}\mu(\frac{T}{d})[h(d)<=p] \]

但是这个\(h(d)\)怎么解决真的不知道。。。p是每次给定的啊。。。
于是抄题解,领会到了神仙们的神仙思维多么强大。
\(2^{18}\)就大于\(500000\)了,所以\(h(i)\)一定都小于18,对于p大于18的,表达式一定恒为真,前缀和预处理前p<=18的情况就好了。。

#include <bits/stdc++.h>
using namespace std;

const int N = 500010;
#define ll long long
int mu[N], T, p[N], cnt;
int h[N], sum[20][N], P;
bool vis[N]; 
ll n, m;

void init() {
	mu[1] = 1;
	for(int i = 2; i < N; ++i) {
		if(!vis[i]) p[++cnt] = i, mu[i] = -1, h[i] = 1;
		for(int j = 1; j <= cnt && i * p[j] < N; ++j) {
			vis[i * p[j]] = 1;
			h[i * p[j]] = h[i] + 1;
			if(i % p[j] == 0) break;
			mu[i * p[j]] = -mu[i]; 
		}
	} 
	for(int i = 1; i < N; ++i) 
		for(int j = i; j < N; j += i) 
			sum[h[i]][j] += mu[j / i];
	for(int k = 0; k <= 18; ++k) 
		for(int i = 1; i < N; ++i)
			sum[k][i] += sum[k][i - 1];
	for(int j = 1; j <= 18; ++j) 
		for(int i = 1; i < N; ++i) 
			sum[j][i] += sum[j - 1][i];
}

ll calc(ll n, ll m, ll lim) {
	ll ans = 0;
	if(n > m) swap(n, m);
	for(ll l = 1, r; l <= n; l = r + 1) {
		r = min(n / (n / l), m / (m / l));
		ans += 1ll * (sum[lim][r] - sum[lim][l - 1]) * (n / l) * (m / l);
	}
	return ans;
}

int main() {
	init();
	scanf("%d", &T);
	while(T--) {
		scanf("%lld%lld%d", &n, &m, &P);
		if(P > 18) printf("%lld\n", n * m);
		else printf("%lld\n", calc(n, m, P));
	}
	return 0;
}
posted @ 2019-02-03 22:51  henry_y  阅读(152)  评论(0编辑  收藏  举报