洛谷 P1217. 回文质数---关于暴力枚举如何优化的问题

[USACO1.5] 回文质数 Prime Palindromes

题目描述

因为 \(151\) 既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 \(151\) 是回文质数。

写一个程序来找出范围 \([a,b] (5 \le a < b \le 100,000,000)\)(一亿)间的所有回文质数。

输入格式

第一行输入两个正整数 \(a\)\(b\)

输出格式

输出一个回文质数的列表,一行一个。

样例 #1

样例输入 #1

5 500

样例输出 #1

5
7
11
101
131
151
181
191
313
353
373
383

提示

Hint 1: Generate the palindromes and see if they are prime.

提示 1: 找出所有的回文数再判断它们是不是质数(素数).

Hint 2: Generate palindromes by combining digits properly. You might need more than one of the loops like below.

提示 2: 要产生正确的回文数,你可能需要几个像下面这样的循环。

题目翻译来自NOCOW。

USACO Training Section 1.5

产生长度为 \(5\) 的回文数:

for (d1 = 1; d1 <= 9; d1+=2) {    // 只有奇数才会是素数
     for (d2 = 0; d2 <= 9; d2++) {
         for (d3 = 0; d3 <= 9; d3++) {
           palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
         }
     }
 }

题解

这道题我做的时候只能通过前九个数据点 最后一组会TLE 本题学习了如何去解决TLE的方法
1. 多加限制条件
2. 先判断容易判断正误的 比如本题回文质数比质数更少 我们就先判断他是不是回文质数 再判断他是不是质数
3. 我们将不同的判断部分分成几个check函数 进行先后check
4. 比我自己写的快一倍左右

P1217-USACO1-5-回文质数-Prime-Palindromes-洛谷-计算机科学教育新生态.png
来自 https://www.luogu.com.cn/article/eksn23nt

#include <bits/stdc++.h>

using namespace std;

int a, b;

bool check1(int x) //判断当前数的位数是否是偶数位 除了11 其余偶数位回文数都不是质数 所以我们从4位开始判断 
{
    //由于本题数据范围只到1e8 所以我们只用判断偶数位 4 和 6 
    if ((1000 <= x && x <= 9999) || (1000000 <= x && x <= 999999)) return false;
    return true;
} 

bool check2(int x) //判断是不是回文数 
{
    int arr[20], flag = 1; //arr[]存x第flag位上的值 从低位向高位存储 
    //将x每一位按顺序存在arr数组里 和我的std::string s = std::to_string(x)类似 
    while (x > 0)
    {
        arr[flag] = x % 10;
        x /= 10; //等同于删去当前位 向高位移动
        flag ++ ; 
    }
    for (int i = 1; i <= flag / 2; i ++ ) //由于上面循环内flag最后++了 所以偶数奇数均适用 比如x有3位就会判断到第2位 
    {
        if (arr[i] != arr[flag - i]) return false;
    }
    return true;
}

bool check3(int x) //判断是不是质数
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )
    {
        if (x % i == 0) return false;
    }
    return true;
}

int main()
{
    scanf("%d%d", &a, &b);
    if (a % 2 == 0) a ++ ; //预处理 由于本题回文数从5开始判断(不用特判a=2的情况)  所有偶数(除了2)都不是质数
    a = min(9999999, a); //额外优化 最大的回文质数是9989899 不加这行也能ac 

    for (int i = a; i <= b; i = i + 2) //这里是i+2 非常巧妙 直接规避了以后++到偶数的情况 
    {
        //从前到后 检验当前数是不是回文质数 
        if (!check1(i)) continue;
        if (!check2(i)) continue;
        if (!check3(i)) continue;
        //顺利通过以上三个检验条件后 就是回文质数 输出 
        printf("%d\n", i); 
    }

    return 0;
}

优化
最大的回文质数_百度搜索.png
自己写的代码只能通过9/10组数据 最后一组会TLE
只需要加上优化就能AC
优化:b = min(9999999, b); 因为最大的回文质数是9989899 但这很取巧

可以记一下的使用方式string s = to_string(i); //将整型转化为字符串形式

#include <bits/stdc++.h>

using namespace std;

int a, b;

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

int main()
{
    scanf("%d%d", &a, &b);
    for(int i = a; i <= b; i ++ )
    {
        if (i % 2 == 0) continue;
        string s = to_string(i); //将整型转化为字符串形式
        for (int j = 0; j < s.size(); j ++ )
        {
            if (s[j] != s[s.size() - 1 - j]) break;
            if (s.size() % 2 == 0)
            {
                if (j == s.size() / 2 - 1)
                {
                    if (is_prime(i))
                    {
                        printf("%d\n", i);
                        break;
                    }
                    break;
                }
            }
            else
            {
                if (j == s.size() - 1 - j)
                {
                    if (is_prime(i))
                    {
                        printf("%d\n", i);
                        break;
                    }
                    break;
                }
            }
        }
    }
    return 0;
}
posted @ 2024-04-16 16:37  MsEEi  阅读(33)  评论(0)    收藏  举报