首页 > 代码库 > SPOJ 74. Divisor Summation 分解数字的因子

SPOJ 74. Divisor Summation 分解数字的因子

本题有两个难点:

1 大量的数据输入,没处理好就超时 - 这里使用buffer解决

2 因子分解的算法 a)暴力法超时 b)使用sieve(筛子),不过其中的算法逻辑也挺不容易搞对的。


数值N因子分解逻辑:

1 保存所有可以sqrt(N)范围内的质素

2 找到可以被N除尽的质素d, 然后用d去除N,使用deg变量,保存度,即有多少个d可以被N除尽

3 用d去乘所有已经找到的因子(包括1),如果度deg大于1,那么循环i从1到deg, 用d*i去乘所有找到的因子

找到所有因子相加,减去N,就是答案。


原题:http://www.spoj.com/problems/DIVSUM/


本题是tutorial题,可以说不是很难的题目,不过看了下提交的记录,超时的2.5万左右,AC的1万左右。


其中包含数学思想的:

-- by Rosen

THE FUNDAMENTAL THEOREM OF ARITHMETIC:

Every integer greater than 1 can be written uniquely as a prime or as the product of two or more primes where the prime factors are written in order of nondecreasing size.

The prime factorizations of 100, 641, 999, and 1024 are given by
100 = 2 · 2 · 5 · 5 = 2 2 5 2 ,
641 = 641,
999 = 3 · 3 · 3 · 37 = 3 3 · 37,
1024 = 2 · 2 · 2 · 2 · 2 · 2 · 2 · 2 · 2 · 2 = 2 10 -- 本题因式分解的基本数学思想

不过本题不单需要质数,而是需要所有能除尽的数,那么就是这些质数组合起来了。


If n is a composite integer, then n has a prime divisor less than or equal to√ n. 

 it follows that an integer is prime if it is not divisible by any prime less than or equal to its square root. This leads to the brute-force algorithm known as trial division.

-- 这个是半暴力法用来找素数(也叫质数)的数学思想


class DivisorSummation47
{
	const static int MAX_BUF = 5120;
	int st, len;
	char inBuf[MAX_BUF];

	const static int FLASH_P = MAX_BUF - 12;
	int oSt;
	char outBuf[MAX_BUF];

	const static int MAX_NUM = 500000;
	bool *sieve;

	char getFromBuf()
	{
		if (st >= len)
		{
			len = fread(inBuf, sizeof(char), MAX_BUF, stdin);
			st = 0;
		}
		return inBuf[st++];
	}
	int intFromBuf()
	{
		char c = getFromBuf();
		while (c < ‘0‘ || ‘9‘ < c && len)
		{
			c = getFromBuf();
		}
		int num = 0;
		while (‘0‘ <= c && c <= ‘9‘ && len)
		{
			num = (num<<3) + (num<<1) + (c - ‘0‘);
			c = getFromBuf();
		}
		return num;
	}

	void wrToBuf(int num, char sep)
	{
		if (oSt > FLASH_P)
		{
			fwrite(outBuf, sizeof(char), oSt, stdout);
			oSt = 0;
		}
		if (0 == num)
		{
			outBuf[oSt++] = ‘0‘;
			outBuf[oSt++] = sep;//漏了这句错误
			return;
		}
		char chs[12];
		int i = 0;
		while (num)
		{
			chs[i++] = num % 10 + ‘0‘;//这里居然忘记步进i错误
			num /= 10;
		}
		for (i--; i >= 0; i--)
		{
			outBuf[oSt++] = chs[i];
		}
		outBuf[oSt++] = sep;
	}
	inline void flashLeft()
	{
		if (oSt) fwrite(outBuf, sizeof(char), oSt, stdout);
	}
public:
	DivisorSummation47() : st(0), len(0), oSt(0)
	{
		int sq = (int)sqrt(double(MAX_NUM));
		sieve = (bool *) calloc(sizeof(bool), sq+1);
		//fill(sieve, sieve+sq+1, false);
		vector<int> primes;
		for (int i = 2; i <= sq; i++)
		{
			if (!sieve[i])
			{
				for (int j = (i<<1); j <= sq; j += i)
				{
					sieve[j] = true;
				}
				primes.push_back(i);
			}
		}

		int T = 0;
		T = intFromBuf();
		while (T--)
		{
			int num = intFromBuf();
			int N = num;
			vector<int> divs(1, 1);
			for (int i = 0; i < (int)primes.size() && num > 1; i++)
			{
				int d = primes[i];
				if (d*d > num) d = num;
				if (num % d == 0)
				{
					int deg = 0;
					for ( ; num % d == 0; num /= d) deg++;
					for (int j = (int)divs.size() - 1; j >= 0 ; j--)
					{
						int t = divs[j];
						for (int k = 0; k < deg; k++)
						{
							t *= d;
							divs.push_back(t);
						}
					}
				}
			}
			int ans = -N;
			for (int i = 0; i < (int)divs.size(); i++)
			{
				ans += divs[i];
			}
			wrToBuf(ans, ‘\n‘);
		}//while(T--)
		flashLeft();
	}
};