机试算法讲解: 第27题 k次方整除

/*
问题:给定n,a求最大的k,使得n!可以被a的k次方整除,但不能被a的k+1次方整除
输入:n(2<=n<=1000),a(2<=a<=1000)
6 10
输出:
1
6!=360.可以被10的1次方整除但是不能被10的2次方整除,
思路:累计除以k次为0,第k+1次不为0(错误)
1 a整除b,b/a 若a中存在素因数px ,则b也必存在该素因数,且该素因数在b中对应的幂指数不小于在a中的幂指数.
要求的k,只需要一次测试a中的每一个素因数,确定b中该素因数对应的幂指数是a栈中幂指数的几倍,所有倍数中最小的那个即为我们要求的k
2 对于a和n!分解素因数。n/(p*p)可以向n!提供两个p银子,但它们在之前(p的倍数必包括p*p的倍数)步骤中每个数都已经向计数器累加了1个p因子,此处
它们还能向计数器贡献n/(p*p)个素因子,累加器累加n/(p*p),若n/(p*p)=0,表示没有一个整数能够向n!提供2个或2个以上的p因子
3 一次遍历可能成为其素因子的素数,计算对应的幂指数,可完成对n!的素因数的分解

不懂
*/

#include <stdio.h>
#include <stdlib.h>
//#include <limits.h>

bool mark[1001];
int prime[1001];
int primeSize;

void init()
{
	int i;
	for(i = 1 ; i <= 1000 ; i++)//要注意初始值
	{
		mark[i] = false;//false表示素数
	}
	for(i = 2 ; i <= 1000 ; i++)//必须从2开始,否则就错了
	{
		if(true==mark[i])
		{
			continue;
		}
		prime[primeSize++] = true;
		for(int j = i*i ; j <= 1000 ; j += i)
		{
			mark[j] = true;
		}
	}
}

int cnt[1001] = {0};//表示n!分解素因数之后,素因子prime[i]对应的幂指数,可能为0
int cnt2[1001] = {0};//表示prime[i]保存的素数在a中的因子数

int main(int argc,char* argv[])
{
	_int64 n,a;
	while(EOF!=scanf("%d %d",&n,&a))
	{
		int i;
		//计数器清零
		for(i = 0 ; i < primeSize ; i++)
		{
			cnt[i] = cnt2[i] = 0;
		}
		//对n!分解素因数,遍历从0到1000的素因数
		for(i = 0 ; i < primeSize ; i++)
		{
			int t = n;//保存n
			//依次计算t/prime[i]的k次方,累加其值,知道t/prime[k]的k次方为0
			while(t)
			{
				cnt[i] += t/prime[i];//如果能整除就加1
				t = t/prime[i];
			}
		}
		//对a分解素因数,计算a中素因数prime[i]对应的幂指数
		//int ans = long_max;
		int ans = 123123123;
		for(i = 0 ; i < primeSize ; i++)
		{
			while(a%prime[i]==0)
			{
				cnt2[i]++;
				a /= prime[i];
			}
			//如果prime[i]不是a的素因数,直接跳过
			if(0==cnt2[i])
			{
				continue;
			}
			//计算素数prime[i]在两个数中因子数的商
			if(cnt[i]/cnt2[i] < ans)
			{
				ans = cnt[i]/cnt2[i];//统计这些商的最小值。因为k最大,所以n!与 a的共有素因数应该最小,次数之差即为
			}
		}
		printf("%d\n",ans);

	}
	getchar();
	return 0;
}

你可能感兴趣的:(k次方整除,机试算法)