[关闭]
@rebirth1120 2019-11-14T08:58:33.000000Z 字数 1362 阅读 717

反素数 解题报告

解题报告


算法进阶指南 反素数

题意

的约数个数,
若对于任意 , 都有 , 则称 为反素数.
给出一个正整数 , 求不大于 的最大反素数.

思路

先考虑把一个数质因数分解, 那么这个数的约数个数就是它的每个质因子个数+1 的乘积.

为我们当前要判断的数, 若存在一个 ,且 , 则 一定不是反素数.

所以我们可以得到一个结论 :
一个反素数的质因子的指数序列一定是一个非升序列.

原因是: 若它不是一个非升序列, 则我们可以将它从大到小排序, 得到一个非升序列, 这个序列所代表的数比原数小, 且它的约数个数和原数相同, 所以原数不是反素数.

又因为 , 所以我们要求的反素数的质因子个数不会超过 10 个, 直接 dfs 就可以了.

其实按照题目的要求, 只要求出第一个比 小的反素数就行了, 但写代码的时候脑抽, 直接把所有反素数求出来然后再 查询...

代码

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. using namespace std;
  4. const int N=1e5+7;
  5. const int M=2000+7;
  6. const int inf=0x3f3f3f3f;
  7. const int lim=2000000000;
  8. int n,pri[40],cnt,v[40],num[M],tot,po[40][40];
  9. void pre(){
  10. for(int i=2;i<=35;i++){
  11. if(!v[i]){ v[i]=i; pri[++cnt]=i; }
  12. for(int j=1;j<=cnt;j++){
  13. if(pri[j]>v[i]||i*pri[j]>35) break;
  14. v[i*pri[j]]=pri[j];
  15. }
  16. }
  17. for(int i=1;i<=cnt;i++){
  18. po[i][0]=1; po[i][1]=pri[i];
  19. int j=1;
  20. while(po[i][j]<=lim&&po[i][j]>0){ po[i][j+1]=po[i][j]*pri[i]; j++; }
  21. }
  22. }
  23. void dfs(int k,ll res,int g,int lst){
  24. if(k>cnt||res>=lim||res<=0) return;
  25. if(res<num[g]){ tot=max(tot,g); num[g]=res;
  26. }
  27. for(int i=lst;i>=0;i--)
  28. dfs(k+1,res*po[k][i],g*(i+1),i);
  29. }
  30. int main(){
  31. // freopen("antiprime.in","r",stdin);
  32. // freopen("antiprime.out","w",stdout);
  33. pre();
  34. memset(num,127,sizeof(num));
  35. dfs(1,1,1,31);
  36. for(int i=tot;i>=0;i--) num[i]=min(num[i],num[i+1]);
  37. tot=unique(num+1,num+1+tot)-num-1;
  38. cin>>n;
  39. int t=lower_bound(num+1,num+1+tot,n)-num;
  40. if(num[t]>n||t>tot) t--;
  41. printf("%d\n",num[t]);
  42. return 0;
  43. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注