题解第八届蓝桥杯B.等差素数列

引用

基金 等差素数列

梦醒时夜续 等差素数列

啰嗦

起初没想明白,居然想着用dfs一个个枚举出等差数列,突然一想,这并不是很现实的。首先你并不知道起始位置在哪,其次公差你也不清楚,所以单是前几个数的排列就够你等的了。有兴趣验证的小伙伴可以试试我的代码,应该是没有问题的,不过懒得等了~

后来看了别人的题解后,发现其实自己一开始就把问题想复杂了。并不需要找排列,只需要确定起始位置是不是素数,然后从公差2开始遍历,寻找后九个数字。由题目的性质我们可以知道,虽然它是填空题,但也肯定能在1~2秒就能跑完,所以数据范围可以定在1e5,而公差可以定在1000以内。

接下来就是判断素数了,可以用线性筛或埃式筛等算法预处理好所有素数,抑或是一个个判断都是可以的(利用它的一对因子中大因子不会大于它的算术平方根 ),也叫试除法

题目描述

2,3,5,7,11,13,… 是素数序列。 类似:7,37,67,97,127,157 这样完全由素数组成的等差数列,叫等差素数数列。

上边的数列公差为 30,长度为 6。

2004 年,格林与华人陶哲轩合作证明了:存在任意长度的素数等差数列。 这是数论领域一项惊人的成果!

有这一理论为基础,请你借助手中的计算机,满怀信心地搜索:

长度为 10 的等差素数列,其公差最小值是多少?

样例

无样例


算法

(线性筛) O ( n ) O(n) O(n)

利用线性筛将素数存到一个数组中,被筛的数存到另一个数组中。

判断的时候直接把起始位置的值当做 a n = a 1 + ( n − 1 ) k a_n = a_1 + (n - 1)k an=a1+(n1)k 中的 a 1 a_1 a1 t + j ∗ k t + j * k t+jk 也就是 a n a_n an ,将其作为索引判断后面九个数是否为素数,如果九个都满足那么此时的公差就是最小公差。

(试除法判断素数) O ( n ) O(\sqrt{n}) O(n )

跟判断质数一样,最多判断 ( n ) \sqrt(n) ( n)

这里的做法和上面类似,直接看代码吧,稍微有一点区别

C++代码

// 线性筛
include <iostream>
using namespace std;

const int N = 1e5 + 10;

int primes[N] , cnt;    // primes[]存储所有素数
bool st[N];             // st[x]存储x是否被筛掉
int flag;

int i , j , k;

void get_primes(int n)
{   

    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)
            st[j] = true;
    }
}

int main()
{

  get_primes(100000);

  for ( i = 0; i < 1000; i ++ ) {
      int t = primes[i];
      for ( j = 2; j < 1000; j ++ ) {
          for ( k = 1; k < 10; k ++ ) {
              if (st[t + j * k]) {
                  break;
              }
          }
           if (k == 10) {
              cout << j;
              return 0;
          }
      }
  }
  return 0;
}
#include<iostream>
#include<cmath>
using namespace std;

bool isPrimeNumber(int t);

int main() {

bool flag = true;
    for (int i = 2; i < 1000; i++) {        // i:起始的素数
        for (int j = 2; j < 1000; j++) {    // j:等差数列公差
            flag = true;
            for (int k = 0; k < 10; k++) {    // k:第k个素数
                if (!isPrimeNumber(i + j * k)) { // 判断等差数列中的数字是否为素数
                    flag = false;
                    break;
                }
            }
            if (flag) { cout << j; break; }  // 输出结果
        }
    }

  return 0;
}

/*
** 判断一个数是否为素数,是则返回true,否则返回false
*/
bool isPrimeNumber(int t) {
    for (int i = 2; i <= sqrt(t); i++) {
        if (t % i == 0)
            return false;
    }
    return true;
}
// 暴力枚举
#include <iostream>
using namespace std;

const int N = 1e5 + 10;

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉
int n = 10;
int perm[N];
int len;

// 线性筛法求素数
void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)
            st[j] = true;
    }
}

// dfs排列型枚举
void dfs(int u , int start)
{
    if(u + len - start < n) return;
    if(u > n)
    {
        int tmp = perm[2] - perm[1] , cnt1 = 1;
        for(int i = 3; i <= n; i ++){
            if (perm[i] - perm[i - 1] != tmp) break;
            else cnt1++;
        }

        if (cnt1 == 9) {
            for (int i = 1; i <= n; i ++)
                printf("%d", perm[i]);
            puts("");
        }
        return ;
    }

    for(int i = start; i < len; i++)
    {
        perm[u] = primes[i];
        dfs(u + 1 , i + 1);
        perm[u] = 0;
    }
}

int main()
{
    // 请在此输入您的代码
    get_primes(100000);
    len = cnt - 1;
    dfs(1 , 0);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值