首页 > 其他分享 >洛谷题单指南-暴力枚举-P1217 [USACO1.5] 回文质数 Prime Palindromes

洛谷题单指南-暴力枚举-P1217 [USACO1.5] 回文质数 Prime Palindromes

时间:2024-02-01 16:22:51浏览次数:30  
标签:Prime Palindromes 标记 int 质数 合数 素数 primes 复杂度

原题链接:https://www.luogu.com.cn/problem/P1217

题意解读:

本题要找[a, b]范围内的所有回文质数,千万不要被题目提示所干扰,如果按照提示先产生各个长度的回文数,再依次判断是否是素数,程序写起来比较繁琐,需要根据a、b的长度,写8个判断是否产生1~8位回文数,最后做素数判断。

换一个思路,先用素数筛法筛出1~最大范围的素数,再去判断每个素数是否是回文数即可。

解题思路:

由于5≤a<b≤100,000,000,因此要筛出108以内的素数,我们知道素数筛算法有三种(后面详解):朴素筛、埃氏筛、线性筛,

朴素筛时间复杂度O(n*logn),埃氏筛时间复杂度O(n*loglogn),线性筛时间复杂度O(n)

对于108数据量,只能用线性筛,而线性筛中涉及两个数组,一个用来保存所有素数,一个用来标记是否是合数,两个数组大小都要开到108,内存限制125M,长度为108的int数组占用空间约为400M,显然不够用。而且108即使用线性筛也基本到了时间复杂度的极限,还要判断回文等操作,有可能超时。

对于回文数,有一个很重要的特定,如果这个数有偶数位,那么一定能被11整除,肯定不是素数,因此,数据最大范围虽然是108,但是8位数肯定不是素数,所以数据最大范围可以缩小为107。对于107数据筛素数,埃氏筛、线性筛都能很好的胜任。

下面重点介绍几个关键知识点:

1、素数筛

所谓素数(质数),是指除了1和它本身以外不再有其他因数的自然数,一般用试除法判断素数(时间复杂度:O(sqrt(n))):

bool isprime(int x)
{
    if(x <= 1) return false;
    for(int i = 2; i * i <= x; i++)
    {
        if(x % i == 0) return false;
    }
    return true;
}

注意:如果i比较大,i * i <= x有溢出风险,写成i <= x / i比较安全。

所谓素数筛,就是在一定范围内,筛出所有的素数。

例如要筛出1~n中所有的素数,如果枚举每一个数去判断是否是素数,时间复杂度为O(n*sqrt(n)),当n=106都无法应对,因此出现了素数筛算法。

素数筛算法的核心思想是通过遍历2~n,将每个数的若干倍数都标记为合数,这样剩下的就都是素数,根据优化程度不同有三种算法:

a、朴素筛法:时间复杂度O(n*logn)

对于2~n中每一个数,如果没有标记成合数,则保存为素数,再将该数的2倍、3倍、4倍...标记为合数,代码如下:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7;

int primes[N], cnt = 1; //保存筛出的素数
bool flag[N]; //标记合数

//朴素筛,筛出1 ~ N之间的素数,复杂度O(nlogn)
void getprimes1()
{
    for(int i = 2; i <= N; i++)
    {
        if(!flag[i]) primes[cnt++] = i; //如果i未被标记合数,则保存i为素数
        for(int j = i + i; j <= N; j += i) //把i的倍数都标记为合数
            flag[j] = true;
    }
}

int main()
{
    getprimes1(); 
    return 0;
}

b、埃氏筛法:时间复杂度O(n*loglogn)

由于在标记合数时,无论当前i时素数还是合数,都将其倍数进行了标记,这样必然导致大量重复标记。

例如:i=2时,i*4=8;而i=4时,又有i*2=8;8被重复标记

埃氏筛就是在朴素筛的基础上做出优化,只将素数的倍数进行标记,合数的倍数不标记,这样可以一定程度减少重复标记,代码如下:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7;

int primes[N], cnt = 1; //保存筛出的素数
bool flag[N]; //标记合数

//埃氏筛,筛出1 ~ N之间的素数,复杂度O(nloglogn)
void getprimes2()
{
    for(int i = 2; i <= N; i++)
    {
        if(!flag[i]) //如果没有被标记为合数
        {
            primes[cnt++] = i; //保存素数
            for(int j = i + i; j <= N; j += i) //只对素数的倍数进行标记
                flag[j] = true;
        }
    }
}

int main()
{
    getprimes2(); 
    return 0;
}

c、线性筛法:时间复杂度O(n)

尽管埃氏筛只针对素数的倍数进行标记,但是还是会有一定程度的重复标记。

例如:i=2时,2*3=6;i=3时,i*2=6;6被重复标记。

线性筛在埃氏筛的基础上又进一步优化,使得每个合数只被它最小的素因子标记,这样每个合数都只被标记一次,如何做到呢?

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7;

int primes[N], cnt = 1; //保存筛出的素数
bool flag[N]; //标记合数

//线性筛,筛出1 ~ N之间的素数,复杂度O(n)
void getprimes3()
{
    for(int i = 2; i <= N; i++)
    {
        if(!flag[i]) primes[cnt++] = i; //如果i未标记为合数,则保存为素数
        for(int j = 1; j <= cnt; j++) //从小到大遍历每一个已保存的素数,要将i * primes[j]标记为合数
        {
            if(i * primes[j] > N) break; //超出最大值
            flag[i * primes[j]] = true; //将i * primes[j]标记为合数,primes[j]必然是i * primes[j]的最小素因子
            if(i % primes[j] == 0) break; //当i中包含一个primes[j]因子,就不能用此i去标记下一个数i * primes[j+1],因为i * primes[j+1]包含因子primes[j],而primes[j+1]不是最小素因子
        }
    }
}

int main()
{
    getprimes3(); 
    return 0;
}

此题任选埃氏筛或者线性筛算法都可以,由于埃氏筛更简单,这里采用埃氏筛。

2、判断回文数

只需要将数字进行翻转,比较翻转后的数字和原来的数字,如果相等则是回文数。

//判断x是否是回文数
bool ispalindrome(int x)
{
    int y = 0; //y是将x各个数字翻转后的数
    int t = x; //先将x复制一份
    while(t)
    {
        y = 10 * y + t % 10;
        t /= 10;
    }
    if(x == y) return true;
    else return false;
}

最后给出完整实现:

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e7;

int primes[N], cnt = 1; //保存筛出的素数
bool flag[N]; //标记非素数
int a, b;

//埃氏筛,筛出1 ~ N之间的素数,复杂度O(nloglogn)
void getprimes2()
{
    for(int i = 2; i <= N; i++)
    {
        if(!flag[i]) //如果没有被标记为合数
        {
            primes[cnt++] = i; //保存素数
            for(int j = i + i; j <= N; j += i) //只对素数的倍数进行标记
                flag[j] = true;
        }
    }
}

//判断x是否是回文数
bool ispalindrome(int x)
{
    int y = 0; //y是将x各个数字翻转后的数
    int t = x; //先将x复制一份
    while(t)
    {
        y = 10 * y + t % 10;
        t /= 10;
    }
    if(x == y) return true;
    else return false;
}

int main()
{
    getprimes2(); //getprimes3();
    cin >> a >> b;

    for(int i = 1; i <= cnt; i++)
    {
        if(primes[i] >= a && primes[i] <= b && ispalindrome(primes[i]))
            cout << primes[i] << endl;
    }

    return 0;
}

 

标签:Prime,Palindromes,标记,int,质数,合数,素数,primes,复杂度
From: https://www.cnblogs.com/jcwy/p/18001508

相关文章

  • C Primer Plus 中文第6版 10.13 第11题
    题目:编写一个程序,声明一个int类型的3*5二维数组,并用合适的值初始化它。该程序打印数组中的值,然后各值翻倍(即是原来的2倍),并显示出各个元素的新值。编写一个函数显示数组的内容,再编写一个函数把各元素的翻倍。这两个函数都以函数名和行数作为参数。分析:写2个函数即可。翻倍函数,用于使......
  • 《C++ Primer Plus》(第六版)中文版——思维导图+附录PDF+源代码
    说明,以下文件可在异步社区免费下载不同之处在于原附录PDF文件没有书签,而本文分享的附录文件带有书签本文所有文件下载链接:https://www.123pan.com/s/lO3uVv-uaEKv.html思维导图(图片)以下仅为预览,高清图片可从文章开头下载链接中下载另外后续本人有空会制作XMind脑图版本,会添加......
  • 还是我们著名的黑券商DOOPrime德璞!让我们看看今天DOOPrime德璞又有什么黑料
    大量客诉!上法制新闻!DOOPrime德璞你可真离谱!是的没错,今天神探要曝光的券商还是DOOPrime德璞!相信通过前面两篇文章,各位投资人已经了解到DOOPrime德璞打擦边球,将已过期的监管牌照拿出来继续宣传这件事!(详情请点击主页查看前两篇文章~)而DOOPrime德璞官方看到了神探的两篇推文,企图通过投......
  • C. Non-coprime Split
    首先,在这道题中,我们首先要把区间内的数字分为两类,包含偶数的区间和不包含偶数的区间。1、包含偶数的区间,我们中需要令a=2,b=i-2。即可符合题意。2、不包含偶数的区间,即只有一个奇数。那么我们要再次分类讨论,若该奇数为质数,贼输出-1;否则拆出它的两个因子(相乘为i)进行化简即可。主......
  • P5736 【深基7.例2】质数筛
    1.题目介绍【深基7.例2】质数筛题目描述输入\(n\)个不大于\(10^5\)的正整数。要求全部储存在数组中,去除掉不是质数的数字,依次输出剩余的质数。输入格式第一行输入一个正整数\(n\),表示整数个数。第二行输入\(n\)个正整数\(a_i\),以空格隔开。输出格式输出一行,依次输......
  • cprimerplus代码相关汇总
    第一章初识C语言重点内容起源:1972,贝尔实验室。继承B语言。特点:功能强大,应用范围广泛。设计步骤:1.定义程序目标2.设计程序3.编写代码4.编译5.运行程序6.测试和调试程序7.维护和修改程序本章小结C是强大而简洁的编程语言。它之所以流行,在于自身提供大量的实用编程工具,能很好......
  • CF1036F Relatively Prime Powers 题解
    题目分析对于一个不合法的数\(x(x\ge2)\),设\(x=\prodp_i^{r_i}\),令\(g=\gcd(r_1,r_2,\ldots,r_k)\),则\(x=\left(\prodp_i^{r_i/g}\right)^g\),所以\(x\)是一个正整数的\(g\)次方。所以可以枚举上文的\(g\),把每一类不合法方案排除掉,就是答案。设\(f(i)\)表示\(2\)......
  • Prime factorization of a number【1月19日学习笔记】
    点击查看代码//Primefactorizationofanumber#include<iostream>#include<cmath>usingnamespacestd;voidprimefactorization(intn){ for(inti=2;i<=sqrt(n);i++){//质因数(除去本身)只可能在根号n及其左侧 if(n%i==0){//i从2开始,短除法 intcou......
  • 质数判断&质因数分解
    引入众所周知,素数的判断在longlong级别是不能\(O(\sqrt{n})\)硬上的。那怎么办呢??参考文献。ababab,先来最低效的。以下复杂度均考虑高精。1.试除法\(O(\sqrtn)\)枚举,\(n\le10^{14}\)。优化只枚举质数,无法优化预处理质数时间。2.Millar-Rabinlonglong:\(O(k\t......
  • [PA2011] Prime prime power
    分析注意到本题用到了常用的一个套路:对\(b\)是否大于\(2\)分类讨论。因为\(b>2\)也就是\(b\ge3\)时\(a\le10^6\),所以考虑把\(3\times10^6\)(因为有\(k\)的存在)前的质数筛出来,暴力找到\(a^b\)加入统计答案的set(\(2^{60}>10^{18}\),因此\(b\le59\))。接下来考虑\(b......