唯一分解定理(数论)

唯一分解定理(数论)_第1张图片

以上内容来自:http://blog.csdn.net/u012860063/article/details/44784031

这个唯一分解定理一般在ACM中经常用到,我在做数论的时候发现还有这么一个东西,本以为要暴力解决的事情(当然超时),现在可以有这么一个定理使用,那可是非常开心了,也就有了下面的详细介绍:

根据上面的定理可知,这种题主要是考察某个数的因数或者因子的问题。

一般情况下呢, 我们首先要进行一次素数打表,然后吧所有的素数放到一个容器内, 然后写一个conf函数求得总的素数因子,然后在暴力计算1-b(最小因子)中能够整除a的,做差得到结果。 下面结合

C - Aladdin and the Flying Carpet

  LightOJ - 1341 
具体解释我会在代码中进行:



#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
#define maxn 1009000
#define INF 0x3f3f3f3f
void find_Prime();//素数打表函数
ll cont(ll a);//计算素数因子

bool book[maxn]; vector v;//book用来筛法打表使用, v则是用来储存素数想见find 函数

ll T, n, m;
int main()
{
	ll T, cas = 0;
	find_Prime();
	cin >> T;
	while(T--)
	{
		cin >> n >> m;
		if(m >= sqrt(n))
		{
			printf("Case %lld: %d\n",++cas,0);
			continue;
		}
		else
		{
			ll cnt = 0;
			for(ll i = 1; i < m; i++)
			{
				if(n % i == 0)
					cnt ++;
			}
			ll sum = cont(n) / 2;// 除2的原因是成对的找
			sum -= cnt;//因为是在m之后寻找,所以要减去m之前的素数因子的个数(对数)
		    printf("Case %lld: %lld\n",++cas,sum);
		}
	}
	return 0;
}

void find_Prime()
{
    //初始化, 打表
	memset(book, 1, sizeof(book));
	for(ll i = 2; i < maxn; i++)
	{
		for(ll j = i * i; j < maxn; j += i)
		{
			book[j] = 0;
		}
	}
    //取出相应的素数
	for(ll i = 2; i < maxn; i++)
	{
		if(book[i] == 1)
			v.push_back(i);
	}
}
ll cont(ll a)
{
	ll s = 1;
    // a == 0 没有素数因子也就返回零就可以了
	if(a == 0)
		return 0;
	ll tt = 0;
	ll i = 0;
	while(v[i] < a && i < v.size())// 条件素数因子应该小于a,并且在我们所打表的范围内
	{
		tt = 0;//计数器用来记录a的素数因子的个数
		if(a % v[i] == 0)// 满足条件
		{
			while(a % v[i] == 0)//循环直到不能被当前的素数整除
			{
				a /= v[i];
				tt++;
			}
		}
		s *= tt + 1;
		i++;
	}
	if(a > 1)
	{
		s *= 1 + 1;
	}
	return s;
}


你可能感兴趣的:(数论基础)