HDU 5750 Dertouzos

HDU5750 Dertouzos

  • 题目描述

A positive proper divisor is a positive divisor of a number n, excluding n itself. For example, 1, 2, and 3 are positive proper divisors of 6, but 6 itself is not.


Peter has two positive integers n and d. He would like to know the number of integers below n whose maximum positive proper divisor is d.

  • Input

There are multiple test cases. The first line of input contains an integer T (1≤T≤106), indicating the number of test cases. For each test case:



The first line contains two integers n and d (2≤n,d≤109).

  • Output

For each test case, output an integer denoting the answer.

  • Sample Input

9

10 2

10 3

10 4

10 5

10 6

10 7

10 8

10 9

100 13

  • Sample Output

1

2

1

0

0

0

0

0

4

  • Tips

题意:

我们把n的不包括其本身的最大因子叫做最大真因子(positive proper divisor),即为PPD(n)。现有i < n,求满足PPD(i) = d的i的个数。


对于一个大于1的正整数d,它总能写成n个质数相乘的形式,即:

F3bUuF.png


则对于所有大于1的素数x ≤ p1,有i = x * d,使PPD(i) = d。下面简要说明:

1° 若x为合数,则能找到x的一个不为1且不为其本身的因子k,设x = x / k,则i = x * (k * d),即PPD(i) ≥ k * d > d,与要求矛盾。

2° 若x为素数,但是x > p1,那么令d = d / p1,则有i = p1 * (x * d ),则有PPD(i) ≥ (x * d ) > d与要求矛盾。


综上,要求满足i < n且PPD(i) = d的数的个数,即要求满足大于1的素数x,且x ≤ p1的个数。

我们可以先用埃式筛法打出素数表(由于测试次数T较大,需要预处理素数表,直接判断素数会TLE)。略微分析一下,可以发现i/d小于1e5,只需打出1e5范围内的素数表就行了。

接着枚举所有素数,判断d mod x是否等于0,如果条件为真,则说明x = p1,计数器+1后结束枚举(在枚举x肯定大于p1了,不满足题意)。由于当x > d时,PPD(i) >= x > d不可能为d,当x * d ≥ n时i = x * d ≥ n不符合题意退出循环。


以上是题意分析,下面简单说明埃式筛法:

埃式筛法的核心一个素数的k(k为大于一的正整数)倍为非素数,将其筛去,这样最后留下的表就是一张素数表了。



误区:

刚开始拿到这道题时,走入了一个误区,认为只要枚举解区间(d, n)内的所有数i,则当n % d == 0 && n / d < d && n/d是素数就是一个满足题意的数。但是却一直TLE。究其原因可能是解区间(d,n)的长度可能非常大(达到1e9),而测试组数又较多,所以导致耗时较长,最后超时。而通过枚举素数,由于1e5范围内的素数个数最大也不过(1e5/2)是个很小的数,很快就能枚举完,所以不会TLE。

  • Answer
#include<bits/stdc++.h>
using namespace std;
const int SIZE = 1e5 + 7;
int prime[SIZE];
bool vis[SIZE]; 
int cnt = 0;
void set_prime(){
	memset(vis, true, sizeof(vis));
	vis[0] = vis[1] = false;
	for(int i = 2; i < SIZE; i++){
		if(vis[i]){	//如果i是素数 
			prime[cnt++] = i;//加入素数表 
			for(int j = i + i; j < SIZE; j += i){//所有i的k(k>=2)被的数肯定不是素数,删掉 
				vis[j] = false;
			}
		}
	}
	return; 
} 
int main(void){
	int t;
	set_prime();//初始化素数表 
	scanf("%d", &t);
	for(int k = 0; k < t; k++){
		int n, d, ans = 0;
		scanf("%d %d", &n, &d);
		for(int i = 0; i < cnt; i++){//枚举x 
			if(prime[i] > d || prime[i] * d >= n) //若x > d,则这之后的PPD肯定不为d,或者,枚举处来的数比n大,则已经枚举结束 
				break;
			if(d % prime[i] == 0){//prime[i]为d的最小素因子,若大于d的最小素因子,则d的最大真约束肯定不为d 
				ans++;
				break;
			}
			ans++;
			
		}
		printf("%d\n", ans);
	} 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值