题意
求[1,n]区间内拥有最多约数的约数的数,输出他和她约数的约数个数,如12的约数1,2,3,4,6,12,这些数有1,2,2,3,4,6个约数,那么12就有18个约数的约数。
对于100%的数据,n<=1e18
题解
暴力还是比较好想
const int maxn=2000005; ll n; ll num[maxn],sum[maxn];//约数个数,约数的约数和 ll ans; int main(){ scanf("%lld",&n); for(int i=1;i<=n;i++){ num[i]++; sum[i]+=num[i]; if(sum[i]>sum[ans]) ans=i; for(ll j=2*i;j<=n;j+=i){ num[j]++; sum[j]+=num[i]; } } //for(int i=1;i<=n;i++) printf("%d ",sum[i]); printf("%d %d",ans,sum[ans]); }
本来想打表发现一些东西,一个答案会管辖区间,1e7内区间才70个不到,而且区间长度就是一些有最多约数的约数的数,本来想从这下手,但是长度也不是单增,就GG了。
正解就是一些数论的东西了。
对于一个数n,可以分解成p1r1p2r2...pmrm,他的约数个数就是(r1+1)(r2+1)....(rm+1)个;
通过上面可以发现,约数个数只与指数有关,所以在约数个数相同时,ri>=ri+1会更优;
根据乘法分配律n的约数和为(1+p1+p12+...p1r1)(1+p2+p22+...p2r2)...(1+pm+pm2+...pmrm),那么类比过来约数的约数个数就是(1+2+..+(r1+1))(1+2+...+(r2+1))...(1+2+...+(rm+1)),可以想象成在每个括号中选一个数,那么就会是一个约数的指数搭配方式,这与最左的数的对应取法得到的约数是一样的。
可以发现这个也只与指数有关,所以ri>=ri+1也会更优
而且1e18的数分成不一样的质数最多到53,那么就可以爆搜了
#include<bits/stdc++.h> using namespace std; #define ll long long ll n; int prime[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; ll ans1,ans2; void dfs(int pos,ll ret,ll num,int last){ if(ret>n) return; if(num>ans2){ ans2=num; ans1=ret; } else if(num==ans2) ans1=min(ans1,ret); for(int i=1;i<=last&&ret<=n/prime[pos];i++){ ret*=prime[pos]; dfs(pos+1,ret,num*((i+1)*(i+2))/2,i); } } int main(){ freopen("b.in","r",stdin); freopen("b.out","w",stdout); scanf("%lld",&n); dfs(1,1,1,60); printf("%lld %lld",ans1,ans2); }