hdoj/hdu 1299 Diophantus of Alexandria(一个数因子个数 + 素数筛选)

 

 超级传送门:

http://acm.hdu.edu.cn/showproblem.php?pid=1299

 

题目大意:

有(1 / x) + (1 / y) = (1 / n),给出n(n < 10 的9次方),问满足上式的x,y有多少组

 

题目分析:

很容易知道:x、y是大于n的;
设y = n + k ( k > = 1),则:x = (n 的平方)  / k + n; 
所以本题关键是找到使x 为整数的k的个数,
也就是找 n平方 的因子 的个数

PS:网上的解题报告中好多人都说质因子,我只敢说因子,但小菜数学不好,不敢说质因子有没有错,

难道质因子的意思就是因子?还是是质数的因子?

言归正传 求一个数的因子数怎么求呢?

引用一个定理

 一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)*...*(rk+1).    可是这个定理的使用范围太小了

那么n*n就是 (p1^r1 * p2^r2 * ... pk^rk  ) *( p1^r1 * p2^r2 * ... pk^rk) ,它的因子的个数就是 (2*r1+1)*(2*r2+1)*...*(2*rk+1).

 

于是重点在于筛选素数:

我用了两个方法学习:筛选法求素数, 随机素数测试;

求素数的方法详细这里就不讨论了。。。

#include<iostream>
#include<cmath>
using namespace std;

//筛选法选素数
const int MAXN = 40000;
bool is[MAXN];int prm[MAXN];

int getprm()
{
	int i,j,k=0;
	int s,e = (int)(sqrt(MAXN+0.0)+1);
	memset(is,1,sizeof(is));
	prm[k++] = 2; is[0] = is[1] = 0;
	for(i=4;i<MAXN;i+=2) is[i] = 0;
	for(i=3;i<e;i++)
	{
		if(is[i] == 1)
		{
			prm[k++] = i;
			for(s = i*2,j=i*i;j<MAXN;j+=s)
			{
				//j,i是奇数,所以j+i*奇数是偶数,不用考虑
				is[j] = 0;
			}
		}
	}
	for(;i<MAXN;i+=2) if(is[i]) prm[k++] = i;
	return k;
}


// 随机素数测试(伪素数原理)
int witness(int a, int n) 
{ 
	int x, d=1, i = ceil(log(n - 1.0) / log(2.0)) - 1; 
	for ( ; i >= 0; i--) { 
		x = d; d = (d * d) % n; 
		if (d==1 && x!=1 && x!=n-1) return 1; 
		if (((n-1) & (1<<i)) > 0) d = (d * a) % n; 
	} 
	return (d == 1 ? 0 : 1); 
} 
int miller(int n, int s = 50) 
{ 
	if (n == 2) return 1; 
	if ((n % 2) == 0) return 0; 
	int j, a; 
	for (j = 0; j < s; j++) { 
		a = rand() * (n-2) / RAND_MAX + 1;  
		//  rand()只能随机产生[0, RAND_MAX)内的整数 
		//  而且这个RAND_MAX只有32768直接%n的话永远也产生不了 
		// [RAND-MAX, n)之间的数  
		if (witness(a, n)) return 0; 
	} 
	return 1; 
}
int getprm2()
{
	int i;
	int k=0;
	for(i=1;i<MAXN;i++)
	{
		if(miller(i) == 1) prm[k++] = i;
	}
	return k;
}

int main()
{
	int i,e,t,n;
	int temp,cn;
	int cnt = 0;
	int sum;
	scanf("%d",&t);
	//cn = getprm(); //筛选法 78MS 288K 
	cn = getprm2(); //随机素数检测(s = 50 156MS 256K)(s=10 93MS 256K )
	while(t--)
	{
		cnt++;
		scanf("%d",&n);
		temp = (int)(sqrt(n+0.0)+1);
		sum = 1;
		for(i=0;i<cn;i++)
		{
			e = 0;
			if(prm[i] > (int)(sqrt(n+0.0)+1)) break;
			while(n % prm[i] == 0)
			{
				n /= prm[i];
				e++;
			}
			sum *= (1+2*e);
		}
		if(n > 1) sum *=3;
		printf("Scenario #%d:\n%d\n\n",cnt,(sum+1)/2);
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值