题意:
给 T 组数据,每组数据含有一个 n,让你求出(d(x)是指 x 的因子个数)
题解:
一看到题目,我们会比较倾向于这样的打表。
void initial()
{
sum[1]=1;
for (int i=2 ; i
然而返回结果,却是一直的TLE,那么显然这样的打表,是行不通的。
我们要更换一下思路,既然这样打表行不通,那么O(n)的线性筛呢?
我们先单独看 只有素因子的数的因子数情况。
例如 4 那么答案是 其中 1 是因子 1 的因子个数,2 是因子 2 的因子个数,3 是因子 4 的因子个数。
可以很容易发现,如果单独是一个素因子构成的数,分解成只有素因子组成的形式,
关键就在于,这样子是否成立。我们暂时忽略掉三次方。
实际上,这式子就是算出 当前被分解的这个数 N 的所有因子数的因子个数的和。
其实这式子,更像是单独求 N 的约数个数这样是把全部因子的权值变为1。
而题目要求的是要知道全部因子数的因子个数,所以给他们附上一定的权值 (自己觉得这里讲的有点牵强,可能需要自己理解一下)。
而根据组合来说,就可以很容易说明这式子的合法性。[实在觉得没办法理解合法性,自己手动写几个例如 12 啊 等等之类的合数,然后数学归纳法归纳一下。]
这个式子是成立的话,那么我们就可以用线性筛来打表了,因为我们 每次只需要知道最小素因子的个数,就可以打表了,跟约数个数是一个原理。证明我之前有一篇写线性筛的博客证明过,就不在这里证明了,有兴趣的可以自己找来看看 (OTL本渣渣写的还可能有错误呢,如果发现错误,麻烦帮忙指出来) 线性筛 [约数个数/约数和]
接下来还要处理三次方的问题。
http://blog.miskcoo.com/2014/09/power-sum
不想直接打表得到结果的,完全可以先筛全部素数,然后暴力分解 N,然后再用上面的式子得到答案。
====================================================================
这些小细节都知道怎么处理了,我们就可以开始打表了。
下面的各种情况,其实跟打约数个数跟约数和的情况是一直的,了解的话,完全可以自己知道式子就能打出来。因为之前写过一篇线性筛的博客,就懒得写的那么详细了。
sum[i]就是 i 的结果
num[i]就是 i 的最小素因子的个数
① n 是素数
那么结果显然是就是 (1+8) 就是说只有自己本身跟 1 这两个因子数,而本身的因子个数为 2。
记录下最小素因子个数。
sum[i]=1+8;
num[i]=1;
② i % prim[j] != 0
因为前面 i 中不存在 prim[j] 这个素因子,但是 i*prim[j] 中存在 prim[j] 这个素因子。
因此结果应该是 sum[i*prim[j]] = sum[i]*sum[prim[j]]
记录下当前最小素因子个数 num[i*prim[j]] = 1
(因为每次扫的必然是最小素因子,至于为什么,本身线性筛就是被最小素因子筛出来的)
③ i % prim[j] == 0
而这种情况,i 中包含了 prim[j] 这个素因子,意味着在最小素因子的那一项,会多了一项
即成了
那么为了得到 i*prim[j] 的结果
我们需要 将 sum[i] / *
那么就需要用到我们之前记录下的最小素因子个数,来得到这个结果。
最后结果 sum[i*prim[j]] = sum[i] / s3(num[i]+1) * s3(num[i]+2) [s3 是用来求的函数]
继续记录下最小素因子个数 num[i*prim[j]] = num[i] + 1
打表结束,我们就可以得到我们需要的答案了。
要说明一下,这个题的内存卡的有点严,如果再开一个数组就会 MLE 所以我没有直接再开一个数组来保存最小素因子那一项的和,而是直接用公式求出。
[OTL 再一次知道线性筛的厉害啊]
打表
#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include