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)\)

与实际情况还是很符合的

posted @ 2021-11-20 17:23  yhang323  阅读(31)  评论(0编辑  收藏  举报