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();
	}
};

SPOJ 74. Divisor Summation 分解数字的因子,布布扣,bubuko.com

时间: 2024-10-29 10:46:31

SPOJ 74. Divisor Summation 分解数字的因子的相关文章

zoj 2095 Divisor Summation

Divisor Summation Time Limit: 5 Seconds      Memory Limit: 32768 KB Give a natural number n (1 <= n <= 500000), please tell the summation of all its proper divisors. Definition: A proper divisor of a natural number is the divisor that is strictly le

line-height属性值为百分比和数字乘积因子的区别

line-height属性值为百分比和数字乘积因子的区别:本章节不对line-height属性的具体用法做介绍,只介绍参数为百分比和数字乘积因子时候的区别.关于line-height的基本用法可以参阅line-height属性深入介绍一章节.当设置line-height属性值为百分比和数字乘积因子的时候有点类似,比如200%和2都可以将line-height属性值设置为当前元素内字体大小的两倍,是不是感觉使用两种方式参数值有点多此一举,其实并非如此.看如下代码实例: <!DOCTYPE html

HDU6623 思维题(n分解成质因子的形式,问最小的幂是多少)

题目大意:给你一个数n,把它分解为素数的幂次的乘积的形式:n=p1^e1 * p2^e2 * .......pk^ek  求最小的幂次是多少 n=le18 分析: 首先我们肯定是不可以枚举1e18的因子的,因为sqrt(1e18)=1e9 ,这样铁超时,那么1s的时间我们是可以预处理出10000以内的素数,我们首先得意思到n在10000以后的素数的幂都不可能大于5了,这很好理解(10001)^5>1e18 , 所以我们可以先用10000以内的素数算出一个最小幂 和剩余数Y, 在枚举看看后面可不可

SPOJ 1029 Matrix Summation【 二维树状数组 】

题意:二维树状数组,更改值的时候有一点不一样, 是将a[x][y]设置为一个值,所以add的时候要将它和以前的值作差一下 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<stack> 6 #include<vector> 7 #include<map> 8 #include<set>

spoj 1029 Matrix Summation

题意: 对一个矩阵有2种操作: 1.把某个元素设为x. 2.查询以(x1,y1)为左上角 以(x2,y2)为右上角的矩阵中的数字的和. 思路: 二维树状数组入门题,同时对横坐标和纵坐标做前缀和就行了. 代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N = 1030; 6 int a[N][N]; 7 int

codeforces 1025B Weakened Common Divisor(质因数分解)

题意: 给你n对数,求一个数,可以让他整除每一对数的其中一个 思路: 枚举第一对数的质因数,然后暴力 代码: #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<d

[质因数分解]UVa10791 Minimum Sum LCM

题目大意 输入整数n (1<=n<2^31),求至少两个正整数,使得它们的最小公倍数为n,且这些整数的和最小,输出最小的和. (LRJ小紫书P317页例题) 思考 看LRJ的分析没怎么看懂,随手搜了一篇题解.发现了一个讲的不错的,让我恍然大悟. 题解地址 首先假设我们知道了一系列数字a1,a2,a3……an,他们的LCM是n,那么什么时候他们是最优解呢,当他们两两互质的时候. 简单证明一下: 设两个正整数为a,b (a<=b) 其gcd(a,b)=n lcm(a,b)=m  sum =

R语言学习(5)-字符串和因子

字符串和因子 1.字符串 创建字符串 > c("HELLO","WORLD") [1] "HELLO" "WORLD" 使用paste函数连接字符串 > paste(c("hello","hi"),"world") [1] "hello world" "hi world" > paste(c("hel

Python 3 生成手写体数字数据集

0.引言 平时上网干啥的基本上都会接触验证码,或者在机器学习学习过程中,大家或许会接触过手写体识别/验证码识别之类问题,会用到手写体的数据集: 自己尝试写了一个生成手写体图片的python程序,在此分享下生成单张 30*30像素的手写体数字1-9图像 的一种实现方法: 我是利用random生成随机数1-9,然后PIL写到图像上,然后经过旋转.扭曲处理,得到"手写体",这里没有加干扰线和干扰点: 得到的手写体数字图像如图1所示: 实现比较简单,用了PIL库,不需要额外安装opencv啥的