CF448E 【Divisors】题解--zhengjun

一道函数递归题

记录一下当前的是第几层和现在要分的数是几(分别用 \(x\)\(y\) 表示)

然后,每一次从小到大枚举因子,继续递归直到输出的总数到达 \(10^5\)

#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
ll a,b,tot;
void dfs(ll x,ll y){
	if(tot>=100000)return;
	if(!x){
		printf("%lld ",y);
		tot++;
		return;
	}
	for(ll i=1;i*i<=y;i++){
		if(y%i)continue;
		dfs(x-1,i);
		if(tot>=100000)return;
	}
	ll k=(ll)(sqrt(y));
	for(ll i=(k*k==y?k-1:k);i>=1;i--){//注意如果这个数是个完全平方数,那么就不能让 sqrt(y) 搜索两次
		if(y%i)continue;
		dfs(x-1,y/i);
		if(tot>=100000)return;
	}
}
int main(){
	scanf("%lld%lld",&a,&b);
	dfs(b,a);
	return 0;
}

然后,你就会发现你稳稳地 \(T\) 了。

我们考虑优化:

  • 如果当前的数 \(y\)\(1\),那么就不用搜索下去了,直接输出 \(1\)

  • 可以先预处理出 \(X\) 的所有因数存在数组 \(p\) 中,那么 \(X\) 的因数的因数 \(\cdots\) 的因数一定是在 \(p\)

  • 枚举每一个 \(X\) 的因数的时候,如果这个因数已经大于 \(y\) 了,就不用再枚举了(后面的一定比前面的大啊)

最终 AC 代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll a,b,tot,p[100001];
void dfs(ll x,ll y){
	if(tot>=100000)return;
	if(!x||y==1){
		printf("%lld ",y);
		tot++;
		return;
	}
	for(ll i=1;i<=p[0]&&p[i]<=y;i++){
		if(y%p[i])continue;
		dfs(x-1,p[i]);
		if(tot>=100000)return;
	}
}
int main(){
	scanf("%lld%lld",&a,&b);
	for(ll i=1;i*i<=a;i++){
		if(a%i==0){
			p[++p[0]]=i;
			if(i*i!=a)p[++p[0]]=a/i;
		}
	}
	sort(p+1,p+1+p[0]);
	dfs(b,a);
	return 0;
}
posted @ 2022-06-11 14:55  A_zjzj  阅读(17)  评论(0编辑  收藏  举报