题目描述

对于任何正整数 xx,其约数的个数记作 g(x)g(x)。例如 g(1)=1g(1)=1,g(6)=4g(6)=4。

如果某个正整数 xx 满足:\forall 0 \lt i \lt x∀0<i<x,都有 g(x) \gt g(i)g(x)>g(i),则称 xx 为反质数。例如,整数 1,2,4,61,2,4,6 等都是反质数。

现在给定一个数 NN,你能求出不超过 NN 的最大的反质数么?

输入格式
一个数 NN。

输出格式
不超过 NN 的最大的反质数。

输入输出样例

输入
1000

输出
840

说明/提示

1 ≤N≤2×109

题意分析:

神奇的结论

int a[]=质数 ,k[]=指数

n= a[1]^k[1] * a[2]^k[2] *……a[n]^k[n]

约数个数 t=(k[1]+1)(k[2]+1)……*(k[n]+1)

枚举每一个质数指数 搜最大答案

转念一想,这虽然比暴力好了许多,不过大概会挂

这时我们就要有一些优化的思路:

这些思路的主旨就是在约数个数相同的情况下尽可能地让当前数小

比如:

1、第一种情况:
6=23 10=25

这是一种约数不同的例子,所以我们枚举质数的时候要从小到大枚举

2、第二种情况:
12=22*3 18=32*2

这时一种指数不同的例子,所以我们就可以推得较大的质数的指数一定小于较小的质数的指数

其实这个很好理解,
就像 2333 比他小的2223 比他小但是因数却和他相等所以他不是反素数。

总结

反素数 质因数的指数一定是递减或者相等的(相等时得比较)。
具体看代码吧

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <bits/stdc++.h>
#define ll long long int
#define sc(a) scanf("%lld",&a)
const int mod=998244353;
using namespace std;
const int inf=1e9+7;
const int maxn=2e5+10;

ll n,m,sum,t,p,res;
ll a[maxn],b[maxn],c[maxn];
ll x,y;
ll dp[110][110];
ll maxx=-1,num=-1;

char str[maxn],s[maxn],ss[maxn];
ll prime[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51};//前二十个素数

void dfs(int a,int b,int c,int d){
	ll i=a,j=0,nt;//a 是开始的值 b 为第几个素数 c 为因子数 d 最大指数也就是上一个的指数 
	while(j<d){
		if(c > maxx || ( c == maxx && a < num)) //两种情况 1, 指数个数比前面的要大,2,指数数相等但这个数比上个数要小 
		 num = a ,maxx = c;//更新小于n的最大反素数 
		j++;
		if(n/i<prime[b]) break;//这个数乘与j会大于n退出 
		nt=c*(j+1);//因子个数 
		i=i*prime[b];//更新这个数;
		if(i<=n) dfs(i,b+1,nt,j);
	}
}
int main(){
	sc(n);
	dfs(1,1,1,30);
	printf("%lld\n",num);
	return 0;
}