P1463 [POI2002][HAOI2007]反素数——题解

LYYY

2018-09-26 20:13:38

Solution

# 打表 我一开始是打算写正解的,但是看了看dalao们的题解,就扼杀了蒟蒻我写正解的想法,于是自己yy了一种打表 ------------ ------------ 相信不会有比我还快用程序打的表了qwq(其实也不算纯打表,完全可以打表顺便AC) ------------ 言归正传 1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260 先给出前几个反质数 我们可以发现相邻两个数之间的差值在近似地增大,为什么说近似呢,因为差值: 1,2,2,6,12,12,12,12,60,60,60,120,360,120,420 我们可以发现:360到720增了360,而720到840只增了120,所以大胆猜想: **相邻两个反质数之间的差值会近似地单调递增,而且数字与差值之间存在一定倍数关系。** 所以我们在枚举(打表)时,不用一个一个地试,可以以之前的差值为单位增加,只尝试以这个差值为倍数的数,使时间复杂度会大大降低。而且合适的取值可以达到2e9内100%的正确率并时间允许。 ### 详见代码: ```cpp #include<cstdio> #include<iostream> using namespace std; int n,last,answer; int chazhi[300]; //存储差值 int head=50,max_i=30; //差值存储从50开始避免越界 //代码核心:因为差值并不是严格上升的,所以通过调用很早记下来的差值保证正确率(尽管会慢,但正确率会变高,用时间换正确率) //ps:max_i的值可自定,2e9的范围100%正确率最小max_i为24,本代码用了30AC,不保险可以用40(但会很慢1min左右,可以先打表再做) //函数名通俗易懂:求x约数个数 int geshu(int x){ int ans=1; for(int i=2;i*i<=x;i++){ int tot=1; while(x%i==0){ x/=i; tot++; } ans*=tot; } if(x!=1)ans<<=1; return ans; } int main(){ scanf("%d",&n); for(int i=1;i<=head;i++) chazhi[i]=1; //初始化为1,先以1位单位增长 for(int i=1;i<=n;i+=chazhi[head-max_i]){ //核心:以往前数第max_i个差值(即chazhi[head-max_i])为单位增长 int lll=geshu(i); if(lll>answer){ chazhi[++head]=i-last; answer=lll; last=i; //更新并存储差值 printf("the %dth answer lower is:%d\n",head-50,last); //该输出为打表 } } printf("%d",last);//答案 return 0; } ``` 附2e9内反质数表 ```cpp //共68个 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 ``` _谢谢阅览_