NOIp2021 T1
考场上的垃圾代码(所以带了freopen)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX=1e7+200;
const int MAXX=1e7+100;
bool del[MAX],flg;
int b[MAXX],d[MAXX],tot,dt,x;
void sheive()
{
b[++tot]=1;
for(int i=2;i<=MAXX;i++)
{
flg=1;
x=i;
while(x)
{
if(x%10==7)
{
flg=0;
break;
}
x/=10;
}
if(flg&&!del[i])
{
b[++tot]=i;
for(int j=1;j<=dt&&(long long)d[j]*i<=MAXX;j++)
{
del[d[j]*i]=1;
}
}
else
{
if(!flg)
{
d[++dt]=i;
for(int j=1;j<=tot&&(long long)b[j]*i<=MAXX;j++)
{
del[b[j]*i]=1;
}
}
for(int j=1;j<=tot&&d[j]<=i&&(long long)d[j]*i<=MAXX;j++)
{
del[d[j]*i]=1;
}
}
}
}
int main()
{
sheive();
freopen("number.out","w",stdout);
freopen("number.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
int x;
scanf("%d",&x);
int wz=lower_bound(b+1,b+tot+1,x)-b;
if(wz>tot||b[wz]!=x) printf("-1\n");
else printf("%d\n",b[wz+1]);
}
}
另外这里再提供一个:
题解部分
首先,这道题我采用的是线性筛
筛完后,直接二分就行了,主代码如下(后面的代码都不加 freopen
了):
int main()
{
sheive();
int T;
scanf("%d",&T);
while(T--)
{
int x;
scanf("%d",&x);
int wz=lower_bound(b+1,b+tot+1,x)-b;
if(wz>tot||b[wz]!=x) printf("-1\n");
else printf("%d\n",b[wz+1]);
}
return 0;
}
那关键就是怎么筛
于是仿照埃筛,就有了如下筛法
void sheive()
{
for(int i=1;i<=MAX;i++)
{
flg=1;
x=i;
while(x)
{
if(x%10==7)
{
flg=0;
break;
}
x/=10;
}
if(flg&&!del[i]) b[++tot]=i;
else if(!flg) for(int j=2;(long long)j*i<=MAX;j++) del[j*i]=1;
}
}
于是,这道题的 AC
的代码就出来了:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX=1e7+100;
bool del[MAX],flg;
int b[MAX],tot,x;
void sheive()
{
for(int i=1;i<=MAX;i++)
{
flg=1;
x=i;
while(x)
{
if(x%10==7)
{
flg=0;
break;
}
x/=10;
}
if(flg&&!del[i]) b[++tot]=i;
else if(!flg) for(int j=2;(long long)j*i<=MAX;j++) del[j*i]=1;
}
}
int main()
{
sheive();
int T;
scanf("%d",&T);
while(T--)
{
int x;
scanf("%d",&x);
int wz=lower_bound(b+1,b+tot+1,x)-b;
if(wz>tot||b[wz]!=x) printf("-1\n");
else printf("%d\n",b[wz+1]);
}
return 0;
}
关于时间复杂度
计算一下以上算法的时间复杂度:
可以根据上面生成的生成的最大数据,当前代码是 \(168\) 毫秒 之间的(比考场上的代码快了一半,考场代码果然太垃圾了)
而 Luogu 的水数据是总共跑了 \(2.07\) 秒的
一共有 \(N\) 个数
设数被删除的概率为 \(d\)
一个数的因数个数的期望为 \(p\)
可以发现,对于每个被删除的数,我们对于它的所有被删除的因数都计算一遍,则时间复杂度为 \(O(dN \times d \times p) = O(d^2pN)\)
在 \(N=10^7\) 时,计算出, \(d \approx 0.0763413366\) ,\(p \approx 25\) ( \(p\) 的估算有些粗略了,离真实值可能有些远),则时间复杂度约为 \(O(1456999.9000000000)\)
与实际情况还是很符合的