……

学习笔记:用线性筛算不太常见的函数

做 ABC 的时候 D 题是板子然而不会,就找到学了一下(考试作弊.jpg

线性筛求一个数 \(a\) 的因子个数 (\(\sigma(a)\)

容易发现当 \(a\in P\) 时,\(\sigma(a)=2\),因为只有 \(1,a\)

按照线性筛的三板斧, \(a\not\in P\) 时,要分两种情况。

\(1.\) \(p\not|\;a\) 那么两数的因子两两组合一定不会重复,即
\(\sigma(a×p)=\sigma(a)×\sigma(p)\)

\(2.\) \(p|a\)

考虑:

\[a=\prod p_i^{k_i} \]

\[\sigma(a)=\prod(k_i+1) \]

那么:

\[\sigma(a*p)=(k_{now}+1+1)\prod\limits_{p\not=p_i}(k_i+1) \]

其中 \(p_{now}=p\)\(p,k\) 下标一一对应。

所以维护一个 \(e\) 数组代表一个数的最小质因子出现的次数,更新比较显然。

\(Code:\)

void get(int n)
{
	t[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!vis[i]) pri[++cnt]=i,t[i]=2,e[i]=1;
		for(int j=1;j<=cnt&&1ll*pri[j]*i<=(ll)n;j++)
		{
			vis[i*pri[j]]=1;
			if(i%pri[j]==0){t[i*pri[j]]=t[i]/(e[i]+1)*(e[i]+2),e[i*pri[j]]=e[i]+1;break;}
			else t[i*pri[j]]=t[i]*2,e[i*pri[j]]=1;
		}
	}
	return;
}

线性筛求一个数 \(a\) 的因子和

为了方便,记:

\[\varepsilon(a)=\sum\limits_{d|a}d \]

即为这个数的约数和。

\(1.\)\(a\in P\) 时,显然 \(\varepsilon(a)=1+a\)

\(2.\)\(a\not\in P, p\not|\;a\) 时,发现从前的因子还是 \(a×p\) 的因子,那么又多了哪些呢?

显然从前的因数 \(s_i×p\)\(a×p\) 的因数,容易证明没有其他的了。
也就是说此时:

\[\varepsilon(a×p)=\varepsilon(a)+\varepsilon(a)×p=\varepsilon(a)(1+p) \]

\(3.\)\(a\not\in P, p|\;a\) 时,这时候如果用上述方法就有重复了...
因为原来的因子与此素数相乘有可能还是原来的因子,这样相加就有重复。
如果不算原来的就会有缺失,那么考虑缺失了哪些?

显然 \(a\) 中不能整除 \(p\) 的因子都会缺失,因为没有其他因子 \(×p\) 成为一个 “不能整除 \(p\) 的因子”。

那我们设 \(e_i\)\(i\) 的因子中不能整除 \(i\) 的最小质因子的因子和。

这里有一个技巧,在线性筛判断整除的时候,如果 i%pri[j]==0 ,这个 pri[j] 一定是 \(i\) 的最小质因子,因为他是第一个能整除的质数嘛。

容易得到,此时:

\[\varepsilon(a×p)=\varepsilon(a)\times p+e_i \]

\(e\) 的更新也比较显然。

\(Code:\)

void get(int n)
{
	t[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!vis[i]) pri[++cnt]=i,t[i]=i+1,e[i]=1;
		for(int j=1;j<=cnt&&1ll*pri[j]*i<=1ll*n;j++)
		{
			vis[i*pri[j]]=1;
			if(i%pri[j]==0){t[i*pri[j]]=t[i]*pri[j]+e[i];e[i*pri[j]]=e[i];break;}
			else t[i*pri[j]]=t[i]*(pri[j]+1),e[i*pri[j]]=t[i];
		}
	}
	return;
}

这个东西比较大,一般要开 long long 的。

posted @ 2020-06-28 09:04  童话镇里的星河  阅读(140)  评论(0编辑  收藏  举报