日常丢出传送门
想更深入的了解反素数什么的看这个分析emmmmmmm
描述
对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。如果某个正整数x满足:g(x)>g(i) 0
Input
一个数N(1<=N<=2,000,000,000)。
Output
不超过N的最大的反质数。
Sample Input
1000
Sample Output
840
分析:
清北考试Day6的T1
梯度比较宜人
暴力找因子最多的可以轻松40分
//TLE
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
#define RI register int
const int sz = 10000010;
inline void read(int &x)
{
x=0;
bool fl=0;
char ch=getchar();
while(ch<'0'||ch>'9')
{if(ch=='-') fl=1;ch=getchar();}
while(ch>='0'&&ch<='9')
{x=x*10+ch-'0';ch=getchar();}
if(fl)
x*=-1;
}
inline void write(int x)
{
if(x<0)
putchar('-'),x*=-1;
if(x/10)
write(x/10);
putchar(x%10+'0');
}
int n,tot,ans,k;
int goal[sz];
inline void fen(int x)
{
for(int i=2;i*i<=n;++i)
{
if(x%i==0)
tot++;
}
if(tot>ans)
goal[++k]=x,ans=tot;
tot=0;
}
int main()
{
read(n);
for(RI ii=sqrt(n);ii<=n;++ii)
fen(ii);
// for(RI ii=1;ii<=k;++ii)
// cout<<goal[ii]<<' ';
// cout<<'\n';
// cout<<k<<endl;
write(goal[k]);
return 0;
}
我们来想想正解(其实是爆搜刷过)
从黄学长博客http://hzwer.com/3141.html里找的一针见血的分析:
一个数约数个数=所有素因子的次数+1的乘积
举个例子就是48 = 2 ^ 4 * 3 ^ 1,所以它有(4 + 1) * (1 + 1) = 10个约数
然后可以通过计算得一个2000000000以内的数字不会有超过12个素因子
并且小素因子多一定比大素因子多要优
预处理出前12个素数直接爆搜即可
还有博客园里一位大佬的分析orz也很到位,蒟蒻看了之瑟瑟发抖http://www.cnblogs.com/tiankonguse/archive/2012/07/29/2613877.html
求[1..N]中最大的反素数–>求约数最多的数
如果求约数的个数 756=2^2*3^3*7^1
(2+1)(3+1)(1+1)=24
基于上述结论,给出算法:按照质因数大小递增顺序搜索每一个质因子,枚举每一个质因子
为了剪枝:
性质一:一个反素数的质因子必然是从2开始连续的质数.
因为最多只需要10个素数构造:2,3,5,7,11,13,17,19,23,29
性质二:p=2^t1*3^t2*5^t3*7^t4…..必然t1>=t2>=t3>=
结果深感恐惧我这爆搜都不敢拿出来。。。太强大了。。。
//正解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
#define ri register int
LL ans,tot,n;
LL su[13]={1,2,3,5,7,11,13,17,19,23,29,31,37};
inline void read(LL &x){
x=0;bool fl=0;char c=getchar();
while(c<'0'||c>'9')
{if(c=='-') fl=1;c=getchar();}
while(c>='0'&&c<='9')
{x=x*10+c-'0';c=getchar();}
if(fl) x*=-1;
}
inline void write(LL x){
if(x<0) putchar('-'),x*=-1;
if(x/10) write(x/10);
putchar(x%10+'0');
}
void dfs(int num,int shu,int yue,int f)
//num是第num个质数,shu是数值,yue是约数个数,f是次方所剩数
{
if(tot<yue || (tot==yue&&ans>shu))
{
tot=yue;
ans=shu;
}
LL j=0,div,i=shu;
while(j<f)
{
j++;
if(n/i < su[num])
break;
div = yue*(j+1);
i = i*su[num];
if(i<=n)
dfs(num+1,i,div,j);
}
}
int main()
{
read(n);
dfs(1,1,1,21);
write(ans);
return 0;
}
下面是zcc老师的std:(小学数学专场)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
long long n, maxd, ans;
int prime[] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
void dfs(int x, long long sum, long long nowd, long long Limit) {
if (nowd > maxd || (nowd == maxd && sum < ans))
maxd = nowd, ans = sum;
if (x > 11) return;
for (int i = 1; sum * prime[x] <= n && i <= Limit; i++)
dfs(x + 1, sum *= prime[x], nowd * (i + 1), i);
}
int main()
{
cin >> n;
ans = 1;
if (n > 1) dfs(1, 1, 1, 1e9);
cout << ans << endl;
return 0;
}
偷偷再附上RQY大佬虐场的代码【跑】
#include <algorithm>
#include <cstdio>
typedef long long LL;
const int M = 19;
const int prime[M] = {
2, 3, 5, 7, 11,
13, 17, 19, 23, 29,
31, 37, 41, 43
};
const int k[M] = {
1, 1, 2, 2, 3,
3, 4, 4, 4, 4,
4, 5, 5, 5
};
const int l[M] = {
5, 4, 3, 3, 2,
2, 2, 2, 2, 2,
2, 2, 2, 2
};
LL n;
LL ansv, anss;
int t[M];
void dfs(int x, LL v, LL s) {
if (s > anss || (s == anss && v < ansv)) {
anss = s;
ansv = v;
}
if (x == M) return;
int bound = 2 * l[x] - 2;
if (x) bound = std::min(bound, std::min(t[x - 1], t[0] / k[x]));
for (t[x] = 1; t[x] <= bound; ++t[x]) {
if ((v *= prime[x]) > n) break;
dfs(x + 1, v, s * (1 + t[x]));
}
}
int main() {
scanf("%I64d", &n);
anss = 0;
dfs(0, 1, 1);
printf("%I64d\n", ansv);
return 0;
}
然后最近又涨了姿势,看到大家很多人是打表过的,对于本题来讲确实有合理性,因为像是6~11之间答案都为6,越往后每个层次差的越大,因此我们暴力找层次再打出表来应该也可以【一个没想到打表的蒟蒻瑟瑟发抖】
打表如下:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int n,ans[500]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,7560,10080,15120,20160,25200,27720,45360,50400,55440,83160,110880,166320,221760,277200,332640,498960,554400,665280,720720,1081080,1441440,2162160,2882880,3603600,4324320,6486480,7207200,8648640,10810800,14414400,17297280,21621600,32432400,36756720,43243200,61261200,73513440,110270160,122522400,147026880,183783600,245044800,294053760,367567200,551350800,698377680,735134400,1102701600,1396755360,2001000000};
int main()
{
cin>>n;
for(int i=0;i<=1000;i++)
if(ans[i]>n)
{
cout<<ans[i-1]<<endl;
return 0;
}
}