题解 P1463 【[POI2002][HAOI2007]反素数】
此题同样是打表,但我们有特殊的打表方法
首先我们可以打个暴力找一下规律,即下面代码中被注释掉的部分,
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int n,i,j,a,maxn=0,num,last;
cin>>n;
i=2;
if(n>=61261200)
i=61261200;
for(;i<=n;)
{
a=i;
num=0;
for(j=2;j<=sqrt(i);j++)
{
if(i%j==0)
num+=2;
if(j*j==i)
num-=1;
}
if(num>maxn)
{
maxn=num;
last=i;
a=i;
/*cout<<i<<" ";
for(j=2;j<=a;j++)
{
if(a%j==0)
{
cout<<j<<" ";
a/=j;
j--;
}
}
cout<<endl;*/
}
if(i>=61261200)
i+=510510;
if(i>=720720&&i<61261200)
i+=30030;
if(i>=55440&&i<720720)
i+=2310;
if(i>=840&&i<55440)
i+=210;
if(i>=180&&i<840)
i+=30;
if(i>=24&&i<180)
i+=6;
if(i<24)
i++;
}
cout<<last;
return 0;
}
大家都知道如果每次i++就是nlogn的暴力,但通过打表我们找到了什么规律呢?
我们可以看到,当i不小于24时,所有的反质数都含有因子2,3
i不小于180时,所有的反质数都含有因子2,3,5
i不小于840时,所有的反质数都含有因子2,3,5,7
以此类推,这样的话我们每次就可以不用i++,而是i+=a,由于越往后a越大,时间复杂度就会很小
同时,当n很大时,我们可以从一个已知的比较大的反质数开始找,这样就可以940ms卡过第二个点