ZZNU-正约数之和(DP)

题目链接

题目描述

我们把f(i)表示为i的正约数的和,而我们要求的是1<=i<=n之间所有i的f(i)之和!

输入

 
  
先输入一个正整数T,表示T个这是数据。T(T<=50)
每行输入一个正整数n。(n<10^6)

输出

输出一个数字,表示所求的数。

样例输入

复制
3
5
12
2018

样例输出

复制
21
127
3350309

刚开是想,对于一个数n,遍历1~n 找它的约数,这样子有太多多余的查找,果然超时了,

其实是可以不用遍历去查找,可以直接找到一个数的约数,

比如: dp[ i*j ]  , i 和 j 就是 i*j 的约数啊~~~~~

用一个双循环,因为约数是成对出现的,,而且 i==j 的时候,只需要加一次,比如 4的约数和 = 1 +2 +4 = 7

所以,双循环中     dp[ i*j ] += j; 最后加 i 或 j 无所谓。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;
const int maxn = 1e6+5;

LL dp[maxn];

void init()
{
	memset(dp,0,sizeof(dp));
	for(int i = 1;i<maxn;i++) //每个数的约数和
    {
		for(int j = 1;j*i<maxn;j++)
		{
				dp[i*j] += j;  //最后加 i 或 j 无所谓
		}
	}
	for(int i = 1;i<maxn;i++)   // 1-n 每个数的约数和的 和
		dp[i] = dp[i-1] + dp[i];
}

int main()
{
	init();
	int t,a;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&a);
		printf("%lld\n",dp[a]);
	}
	return 0;
 }

猜你喜欢

转载自blog.csdn.net/qq_41003528/article/details/80297032