反素数求解+反素数打表
问题描述:
对于任何正整数x,起约数的个数记做g(x).例如g(1)=1,g(6)=4.
如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x),则称x为反素数.
现在给一个N,求出不超过N的最大的反素数.
比如:输入1000 输出 840
思维过程:
求[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 <cstdio> #include <cstring> #define ll long long using namespace std; const int inf = 999999999; const int prime[16]= {1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47}; int n; ll bnum,bsum; //当前枚举到的数;枚举到的第K大的质因子;该数的约数个数;质因子个数上限。 void getantiprime(ll num,ll k,ll sum,ll limit) { //如果约数个数更多,将最优解更新为当前数。 if (bsum < sum) { bsum = sum; bnum = num; } //如果约数个数相同,将最优解更新为较小的数。 if (bsum == sum && bnum > num) bnum = num; if (k > 10) return ; ll tmp = num; //开始枚举每个质因子的个数。 for (int i = 1; i <= limit; ++i) { if (tmp*prime[k] > n) break; tmp = tmp*prime[k]; getantiprime(tmp,k + 1,sum*(i + 1),i); } } int main() { int t; scanf("%d",&t); while (t--) { bsum = -inf; bnum = inf; scanf("%d",&n); getantiprime(1,1,1,50); printf("%lld\n",bnum); } return 0; }
反素数打表函数:
#include<iostream> #include<cstring> #include <cstdio> #define maxn 600000 using namespace std; int dp[600001]; int main() { int i,j; freopen("out.txt","w",stdout); memset(dp,0,sizeof(dp)); for(i=1;i<=maxn;i++) { for(j=1;i*j<=maxn;j++) { dp[i*j]++; } } int max=0; for(i=2;i<=maxn;i++) { if(dp[i]>max) { max=dp[i]; cout<<i<<","; } } cout<<endl<<endl; max=0; for(i=2;i<=maxn;i++) { if(dp[i]>max) { max=dp[i]; cout<<dp[i]<<","; } } return 0; }
int antip[] = {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};
int pnum[] = {1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,
60,64,72,80,84,90,96,100,108,120,128,144,160,168,180,192,200,
216};