Solution [POI2002][HAOI2007]反素数
题目大意:设\(x\)的约数个数为\(g(x)\),若对于所有\(i \in [1,x)\),都有\(g(i) < g(x)\),则称\(x\)为反素数,求不超过\(n\)的最大反素数
分析:这道题可以打表,但是打表也要讲求方法
对于\(n = 2 \times 10^9\)这种级别的数据,如果你用\(O(n^2)\)算法,估计你得搬出太湖之光才能以可以接受的速度跑完(而且你还得考虑并行计算效率问题)
我们把这个问题分成两部分解决:
- 预处理出\(g\)
- 计算反素数
对于第一个问题,我们可以利用筛法的思想,对于每个数,我们枚举它的倍数,然后累加,复杂度略超埃氏筛
准确来讲是\(\sum_1^n\frac{n}{i}\),然后这玩意儿接近\(nlogn\)(具体怎么证明蒟蒻真不会,从某篇博客上看到的)
对于计算反素数我们保存一个到当前位置的最大值就可以了
我们可以用\(unsigned\;short\)来保存\(g\),这样常数会小一些(缓存优化)
亲测比用\(int\)的要快\(80s\)左右
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned short type;
const int maxn = 2e9 + 100;
type *num;
int main(){
freopen("fafa.out","w",stdout);
num = new type[maxn];//这里最好动态分配内存,貌似Windows平台 or 比较老旧的编译器无法编译大数组?我之前CE过
memset(num,0,sizeof(type) * maxn);//既然动态分配了那就要清0
for(int i = 1;i <= maxn;i++){
for(int j = 1;j * i <= maxn;j++)
num[j * i]++;
}
type mx = 0;//unsigned不能赋值为-INF
for(int i = 1;i <= maxn;i++){
if(mx < num[i])printf("%d,",i);
mx = max(mx,num[i]);
}
printf("\n");
fflush(stdout);
fclose(stdout);
return 0;
}
然后我本机跑了\(320s\)左右就打出来了一个表
然后程序就很明了(话说这题打表不会棕吧?)
#include <algorithm>
#include <cstdio>
using namespace std;
int n,i,arr[] = {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,0x7fffffff};//放置一个无穷大的哨兵,不然会RE第二个点
int main(){
scanf("%d",&n);
while(arr[i + 1] <= n)i++;
return printf("%d\n",arr[i]),0;
}
话说小数据二分查找没用诶,我用了二分反而跑的更慢了,不知道那些\(0\;ms\)的神仙怎么跑出来的(上一代评测姬的锅?)
原文地址:https://www.cnblogs.com/colazcy/p/11515099.html
时间: 2024-09-30 05:35:19