【bzoj 1053/P1463】反素数 HAOI2007(爆搜)

日常丢出传送门

想更深入的了解反素数什么的看这个分析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;
        }
}
发布了75 篇原创文章 · 获赞 80 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_36693514/article/details/78273235
今日推荐