icodelab 找朋友(P4397 [JLOI2014]聪明的燕姿)
描述
老师给每个同学一个号码牌,假设小明的号码牌上写着数字 S,那么其他那些手上的号码牌数字的所有正约数之和等于 S的同学就是小明的朋友。
输入
输入包含 k 组数据。 对于每组数据,输入包含一个数字S。
输出
对于每组数据,输出有两行,第一行包含一个整数 m,表示有 m 个小明的朋友。
第二行包含相应的 m 个数,表示小明朋友的手中的数字。
注意:你输出的数字必须按照升序排列。
输入样例 1
42
输出样例 1
3 20 26 41
提示
对于 100%的数据,k≤100, S≤2×10^9
思路
对于一个数 NN ,如果它的标准分解式为 N=p1a1p2a2p3a3…pnan 那么约数和
S=∏i=1n∑j=0aipijS=\begin{matrix} \prod_{i=1}^n \end{matrix}\begin{matrix} \sum_{j=0}^{a_i} {p_i}^j \end{matrix}( p1p_1 、 p2 、… pn为质数)
因为 S<=2∗109S<=2*10^9,然后多试几组数据就会发现 NN, 、SS同级,所以 pi≤S{p_i}\leq\sqrt{S}
于是考虑暴搜,先筛出 ≤S\leq\sqrt{S} 的所有质数,先枚举 pi,对于每个 pip_i,枚举 aia_i暴搜,如果搜到S==1 的话,答案++
特别的,如果 S−1S-1为质数,且 S−1≥ 当前要搜的质数,答案也要++,此时的数为
已搜出的数*( S−1S-1)
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000010;
long long q;
bool vis[N+5];
int m,flag=0,tot=0;
int a[(N+5)<<2],pr[N+5];
bool check(int x) {
if(x==1)
return 0;
if(x<=N)
return !vis[x];
for(int i=1; pr[i]*pr[i]<=x; ++i)
if(x%pr[i]==0) return 0;
return 1;
}
void dfs(long long now,int x,long long y) {
if(now==1) {
a[++flag]=y;
return;
}
if(now-1>=pr[x] && check(now-1))
a[++flag]=y*(now-1);
int i;
long long p,tmp;
for(i=x; pr[i]*pr[i]<=now; ++i) {
tmp=pr[i];
p=pr[i]+1;
for(; p<=now; tmp*=pr[i],p+=tmp)
if(now%p==0)
dfs(now/p,i+1,y*tmp);
}
return;
}
int main() {
for(int i=2; i<=N; i++) {
if(!vis[i])
pr[++tot]=i;
for(int j=1; j<=tot&&i*pr[j]<=N; j++) {
vis[i*pr[j]]=1;
if(i%pr[j]==0)
break;
}
}
while(~scanf("%d",&m)) {
q=sqrt(m);
memset(a,0,sizeof(a));
flag=0;
dfs(1LL*m,1,1LL);
printf("%d\n",flag);
sort(a+1,a+flag+1);
for(int i=1; i<flag; i++)
printf("%d ",a[i]);
if(flag)
printf("%d\n",a[flag]);
}
return 0;
}
对于一个数NNN,如果它的标准分解式为N=p1a1p2a2p3a3…pnanN=p_1^{a_1}p_2^{a_2}p_3^{a_3}…p_n^{a_n}N=p1a1p2a2p3a3…pnan 那么约数和
S=∏i=1n∑j=0aipijS=\begin{matrix} \prod_{i=1}^n \end{matrix}\begin{matrix} \sum_{j=0}^{a_i} {p_i}^j \end{matrix}S=∏i=1n∑j=0aipij(p1p_1p1、p2p_2p2、…pnp_npn为质数)
因为S<=2∗109S<=2*10^9S<=2∗109,然后多试几组数据就会发现NNN、SSS同级,所以pi≤S{p_i}\leq\sqrt{S}pi≤S
于是考虑暴搜,先筛出≤S\leq\sqrt{S}≤S
的所有质数,先枚举 pip_ipi,对于每个pip_ipi,枚举aia_iai暴搜,如果搜到S==1S==1S==1的话,答案+1
特别的,如果S−1S-1S−1为质数,且S−1≥S-1\geS−1≥当前要搜的质数,答案也要+1,此时的数为
已搜出的数*(S−1S-1S−1)

浙公网安备 33010602011771号