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_1p2 、… 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=p1a1p2a2p3a3pnan 那么约数和

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=1nj=0aipijp1p_1p1p2p_2p2、…pnp_npn为质数)

因为S<=2∗109S<=2*10^9S<=2109,然后多试几组数据就会发现NNNSSS同级,所以pi≤S{p_i}\leq\sqrt{S}piS

于是考虑暴搜,先筛出≤S\leq\sqrt{S}S

的所有质数,先枚举 pip_ipi,对于每个pip_ipi,枚举aia_iai暴搜,如果搜到S==1S==1S==1的话,答案+1

特别的,如果S−1S-1S1为质数,且S−1≥S-1\geS1当前要搜的质数,答案也要+1,此时的数为

已搜出的数*(S−1S-1S1

猜你喜欢

转载自www.cnblogs.com/mysh/p/11306299.html