TIMUS-1748. The Most Complex Number-求反素数(数学+搜索)

http://acm.timus.ru/problem.aspx?space=1&num=1748

 

题意:给定一个数n,要求一个不超过n的数,并且因子数最多的最小的数。

也就是反素数

根据反素数的性质,每个反素数必然是由一系列【连续】质因子组成,并且较小的因子的次数一定比较大的因子的次数大 (不满足这两个条件必然可以找到一个 更小的数 且因子数与该数相同 ,矛盾)


所以我们dfs搜即可。

搜索控制两个条件

1:第k个因子的最高次比k-1的最高次低

2:因子数的话,可以根据 定理1: 一个正整数 n 可以用***素***因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)~(rk+1).来求



搜索过程的话,如果发现当前乘积已经大于n了,就可以break掉

本题数据比较大。 这个判断用乘法会溢出,所以改用除法就好了



0.28s

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
#define ll __int64
#define ull unsigned __int64
const double pi=acos(-1.0);
double eps=0.000001;
int prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
ll ans;
ll num;
ll n;
void dfs(int k, ll now,ll cnt,int last)//求1-n最大反素数,初始化ans=n,num=1
//k是层数,now是当前的乘积,cnt是当前的数对应的因子数,last是最后一个因子的最高次数
{ 
	if (now>n) return; //剪枝,比判k==17快
	//if (k==17) return ;
	if ( cnt>num)		//更新答案
	{ 	ans=now;num=cnt;}
	else
		if(cnt==num)
		{
			if (now<ans)
				ans=now;
		} 
		ll t=prime[k],i;	//t是素因子的方幂
		for (i=1;i<=last;i++)	//last是最高次,显然当前素因子最高次不超过前面的最高
		{
			if (t>n/now) break;		//乘法溢出
			dfs(k+1,now*t,cnt*(i+1),i);
			t*=prime[k]; 
		}
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		num=1;
		scanf("%I64d",&n);
		ans=n;
		dfs(1,1,1,60);
		printf("%I64d %I64d\n",ans,num);
	}
	
	return 0;
	
}


你可能感兴趣的:(TIMUS-1748. The Most Complex Number-求反素数(数学+搜索))