SP530 DIV2 - Divisors 2

原题链接

题意简述

\(d(n)\)\(n\) 的因数个数。若 \(d(n) > 3\),且对于所有的 \(m\ |\ n\),都有 \(d(m)\ |\ d(n)\),则称 \(n\) 为特殊的数。

\([1,10^6]\) 内所有的特殊的数。为减小输出量,只需在每 \(108\) 个特殊的数中输出第 \(108\) 个即可。

题目分析

\(n = p_1^{\alpha_1} \times p_2^{\alpha_2} \times \cdots \times p_{k}^{\alpha_k}(\alpha_1,\alpha_2,\cdots,\alpha_k \geq 1)\),则 \(d(n) = (\alpha_1+1)(\alpha_2+1) \cdots (\alpha_k+1)\)

根据题意,若 \(n\) 为特殊的数,则对于所有的 \(m\ |\ n\),都有 \(d(m)\ |\ d(n)\)

\(m = p_1^{\beta_1} \times p_2^{\beta_2} \times \cdots \times p_{k}^{\beta_k}(\beta_i \leq \alpha_i,i \in [1,k])\),则 \(d(m) = (\beta_1+1)(\beta_2+1) \cdots (\beta_k+1)\)

所以 \(d(m)\ |\ d(n) \Leftrightarrow (\beta_1+1) \cdots (\beta_k+1)\ |\ (\alpha_1+1) \cdots (\alpha_k+1)\)

不妨令 \(\beta_1 = \alpha_1,\beta_2 = \alpha_2,\cdots,\beta_{k-1} = \alpha_{k-1},\beta_k = \alpha_k-1\)

所以 \((\alpha_1+1) \cdots (\alpha_{k-1}+1)\alpha_k\ |\ (\alpha_1+1) \cdots (\alpha_{k-1}+1)(\alpha_k+1)\)

\(\Rightarrow \alpha_k\ |\ \alpha_k+1\)

\(\Rightarrow \alpha_k\ |\ 1\)

\(\Rightarrow \alpha_k = 1\)

神奇的事情发生了!我们将特定的 \(m\) 代到关系式,最终可以得到 \(\alpha_k = 1\)

同理,可以得到 \(\alpha_i = 1(i \in [1,k])\)

所以 \(n = p_1 \times p_2 \times \cdots \times p_k\)\(p_i\) 为质数),\(d(n) = 2^k\)

又因为 \(d(n) > 3\),所以 \(k \geq 2\),即 \(n\) 不能为质数。

容易知道,这种形式的 \(n\) 肯定是符合要求的。

所以我们要找 \([1,10^6]\) 内不为质数,且分解质因数后所有质因子的次数均为 \(1\) 的数。

怎么找呢?从反面考虑,可以把所有质数以及能被质数平方整除的数排除掉。

对于质数,我们直接用线性筛。

对于能被质数平方整除的数,我们将目光放到线性筛的几行代码:

ck[i*pri[j]]=1;
if(i%pri[j]==0) break;

首先 i * pri[j] 这个数肯定能被 pri[j] 整除,那如果 i % pri[j] == 0 呢?说明 i 这个数肯定也能被 pri[j] 整除,所以 i * pri[j] 能被 pri[j] * pri[j] 整除,它就不是一个特殊的数,把它标记一下就行了。于是就有了下面的代码:

ck[i*pri[j]]=1;//ck是标记质数的数组
if(i%pri[j]==0) pd[i*pri[j]]=1;//pd是标记特殊的数的数组

去掉 break 是因为其他数可能会在这个循环内被标记,但是在其他循环内不被标记,与判断合数不同(自己想一想就知道了)。

代码较丑,勿喷

代码

#include<bits/stdc++.h>
using namespace std;
namespace my_std{
	#define ll long long 
	#define bl bool
	#define pc putchar
	#define fr(i,x,y) for(register ll i=(x);i<=(y);i++)
	#define enter pc('\n')
	#define il inline
	il ll read(){
		ll sum=0,f=1;
		char ch=0;
		while(!isdigit(ch)){
			if(ch=='-') f=-1;
			ch=getchar();
		}
		while(isdigit(ch)){
			sum=sum*10+(ch^48);
			ch=getchar();
		}
		return sum*f;
	}
	il void write(ll x){
		if(x<0){
			x=-x;
			pc('-');
		}
		if(x>9) write(x/10);
		pc(x%10+'0');
	}
	il void writeln(ll x){
		write(x);
		enter;
	}
}
using namespace my_std;
ll pri[1000010],cnt=0,ans[1000010],tot=0;
bl ck[1000010],pd[1000010];//ck是标记质数的数组,pd为标记特殊的数的数组,0为是,1为不是 
int main(){
	pd[1]=1;//1肯定不是特殊的数,要去掉 
	fr(i,2,1e6){
		if(!ck[i]){
			pri[++cnt]=i;
			pd[i]=1;//把质数去掉 
		}
		fr(j,1,cnt){
			if(i*pri[j]>1e6) break;
			ck[i*pri[j]]=1;
			if(i%pri[j]==0) pd[i*pri[j]]=1;//如上面解释 
		}
	}
	fr(i,1,1e6) if(!pd[i]) ans[++tot]=i;
	for(ll i=108;i<=tot;i+=108) writeln(ans[i]);
}
posted @ 2021-09-07 19:56  AFewSuns  阅读(44)  评论(0编辑  收藏  举报