【HAOI2007】反素数

原题:

 

最开始觉得要么是个公式,要么是个结论

结果研究了半天越推越奇怪,这不会是个dp吧……

先按下不表,研究性质还是可以得到很有用的信息的

1.结论,令h(x)表示因子个数为x的反质数,则h(x)是单调的(h函数的定义域并不是正整数,在有值的地方是单调的)

这个结论看上去很显然,但是它传递出一个关键的信息:找出最大的h(x)等价于找出最大的x

2.如果h(x)的质因子幂之积为2^k1*3^k2*5^k3*...(k可以为0),那么x=(k1+1)*(k2+1)*(k3+1)*...

想到这里就可以开始DP了

接下来只需令f[i]表示因子个数为i的最小的数,那么由性质2可以很轻松地进行转移

最后只需从高到低扫描f[i],取出不大于n的最大值即可,这样做的正确性已经由性质1保证

代码:(写代码的时候思路还不是很清晰所以代码比较丑)

 1 #include<iostream>
 2 #include<cstdio>
 3 #define LL long long
 4 using namespace std;
 5 const int oo=2000000007;
 6 int n;
 7 LL f[2][5100];
 8 int pr[110000],pt=0;
 9 int pf[110000];
10 void gtp(){
11     for(int i=2;i<=100000;++i){
12         if(pf[i]==0)  pr[++pt]=i;
13         for(int j=1;j<=pt && pr[j]*i<=100000;++j){
14             pf[i*pr[j]]=1;
15             if(i%pr[j]==0)  break;
16         }
17     }
18 }
19 int main(){
20     gtp();
21     for(int i=1;i<=5000;++i){
22         f[0][i]=oo;
23         f[1][i]=oo;
24     }
25     scanf("%d",&n);
26     f[0][1]=1;
27     for(int i=1;i<=5000;++i){
28         LL bwl=1;
29         for(int j=0;;++j){
30             for(int k=1;k<=5000;++k)if(k*(j+1)<=5000)
31                 f[i&1][k*(j+1)]=min(f[i&1][k*(j+1)],f[i&1^1][k]*bwl);
32             bwl*=pr[i];
33             if(bwl>n)  break;
34         }
35     }
36     //for(int i=1;i<=20;++i)  cout<<f[1000][i]<<" ";
37     //cout<<endl;
38     for(int i=5000;i>=1;--i)if(f[0][i]<=n){
39         printf("%lld
",f[0][i]);
40         break;
41     }
42     return 0;
43 }
View Code
原文地址:https://www.cnblogs.com/cdcq/p/13811660.html