P1463 [POI2001][HAOI2007]反素数
written on 2022-05-22
很早以前就想写这题了,刚好昨天比赛碰见,于是写一下总结。
刚开始没有想到正解,于是敲了打表,骗了80pts。正确的打表方式……见代码吧
#include<bits/stdc++.h>
using namespace std;
int a[100]={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};
/*
int work(int x)
{
int cnt=0;
for(int i=1;i<=sqrt(x);i++)
{
if(x%i) continue;
cnt++;
if(i*i!=x) cnt++;
}
return cnt;
}
int F(int x)
{
if(x<6) return 1;
if(x<240) return 6;
if(x<1680) return 60;
if(x<110880) return 120;
return 27720;
}*/
int main()
{
/*
int mx=0,p=0;
for(int i=1;i<=2e9;i+=F(i))
{
int x=work(i);
if(x>mx) mx=x,printf("%d,",i),p++;
}
printf("num=%d\n",p);*/
int n;
scanf("%d",&n);
int l=0,r=67,ans;
while(l<=r)
{
int mid=l+r>>1;
if(a[mid]<=n) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n",a[ans]);
}
另外,正解需要涉及一些数学知识,这里引用一篇优质题解(感谢@_wkjzyc)。
正解的关键在于发现一个数因数个数与质因子之间的关系,也就是这篇题解中所写的第三点,原因是质因子的排列组合组成所有因数。用搜索的方法,要处理的数就会大大减少。另外还要发现指数的单调性与质数的连续性,这里题解中都有涉及到,不再赘述。
贴一下自己的低效代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int p[]={2,3,5,7,11,13,17,19,23,29};
vector<ll> v;
int work(int x)
{
int cnt=0;
for(int i=1;i<=sqrt(x);i++)
{
if(x%i) continue;
cnt++;
if(i*i!=x) cnt++;
}
return cnt;
}
ll power(int a,int b)
{
if(!b) return 1;
ll res=1;
while(b)
{
if(b&1) res=res*a;
a=a*a;
b>>=1;
}
return res;
}
void dfs(ll now,int id,int mn)
{
if(now>2e9||id>=10||now<=0) return ;
v.push_back(now);
for(int i=1;i<=mn;i++) dfs(now*power(p[id],i),id+1,i);
}
vector<int> g;
int main()
{
ll p=1;
dfs(1ll,0,31);
sort(v.begin(),v.end());
int mx=0;
for(int i=0;i<v.size();i++)
{
int x=work(v[i]);
if(x>mx) g.push_back(v[i]),mx=x;
}
// for(int i=0;i<g.size();i++) printf("%d ,",g[i]);
int n;
scanf("%d",&n);
int l=0,r=g.size()-1,ans;
while(l<=r)
{
int mid=l+r>>1;
if(g[mid]<=n) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",g[ans]);
}
以及自己的高效代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int p[]={2,3,5,7,11,13,17,19,23,29};
ll power(int a,int b)
{
if(!b) return 1;
ll res=1;
while(b)
{
if(b&1) res=res*a;
a=a*a;
b>>=1;
}
return res;
}
int n,mx;
ll ans;
void dfs(ll now,int id,int mn,int cnt)
{
if(now>n||id>=10||now<=0) return ;
if(cnt>mx||(cnt==mx&&now<ans)) mx=cnt,ans=now;
for(int i=1;i<=mn;i++) dfs(now*power(p[id],i),id+1,i,cnt*(i+1));
}
int main()
{
scanf("%d",&n);
dfs(1,0,30,1);
printf("%lld\n",ans);
}