week17--素数-相关习题整理

3 篇文章 0 订阅

整理了几道素数筛法相关的几道练习题

[蓝桥杯 2021 省 AB2] 完全平方数

题目描述

一个整数 a a a 是一个完全平方数,是指它是某一个整数的平方,即存在一个 整数 b b b,使得 a = b 2 a=b^{2} a=b2

给定一个正整数 n n n,请找到最小的正整数 x x x,使得它们的乘积是一个完全平方数。

输入格式

输入一行包含一个正整数 n n n

输出格式

输出找到的最小的正整数 x x x

样例 #1

样例输入 #1

12

样例输出 #1

3

样例 #2

样例输入 #2

15

样例输出 #2

15

提示

对于 30 % 30 \% 30% 的评测用例, 1 ≤ n ≤ 1000 1 \leq n \leq 1000 1n1000,答案不超过 1000 1000 1000

对于 60 % 60 \% 60% 的评测用例, 1 ≤ n ≤ 1 0 8 1 \leq n \leq 10^{8} 1n108,答案不超过 1 0 8 10^{8} 108

对于所有评测用例, 1 ≤ n ≤ 1 0 12 1 \leq n \leq 10^{12} 1n1012,答案不超过 1 0 12 10^{12} 1012

蓝桥杯 2021 第二轮省赛 A 组 G 题(B 组 H 题)。

#include <bits/stdc++.h>
using namespace std;
/*
给我这个数学不好的菜狗一点小小的数论震撼
完全平方数如果进行因数分解的话
所有因子都是有偶数个的

对n进行质因数分解
若质因子指数为偶数
则对结果无影响
若质因子指数为奇数
则在x中乘以这个质因子
保证指数为偶数
另外我这题爆int了
然后for循环判断条件就乱了
评测机显示TLE导致我de不出来
*/


long long n;
long long ans = 1;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> n;
    
    //这个循环条件有门道的
    for(long long i = 2; i * i <= n; i ++) {
        if(n % i == 0) {
            int cnt = 0;
            while(n % i == 0) n /= i, cnt ++;
            if(cnt % 2) ans *= i;
        }
    }

    //要注意n未除完的情况
    if(n != 1) ans *= n;
    cout << ans;


    return 0;
}

哥德巴赫猜想(升级版)

题目背景

1742 年 6 月 7 日,哥德巴赫写信给当时的大数学家欧拉,正式提出了以下的猜想:任何一个大于 9 9 9 的奇数都可以表示成 3 3 3 个质数之和。质数是指除了 1 1 1 和本身之外没有其他约数的数,如 2 2 2 11 11 11 都是质数,而 6 6 6 不是质数,因为 6 6 6 除了约数 1 1 1 6 6 6 之外还有约数 2 2 2 3 3 3需要特别说明的是 1 1 1 不是质数。

这就是哥德巴赫猜想。欧拉在回信中说,他相信这个猜想是正确的,但他不能证明。

从此,这道数学难题引起了几乎所有数学家的注意。哥德巴赫猜想由此成为数学皇冠上一颗可望不可及的“明珠”。

题目描述

现在请你编一个程序验证哥德巴赫猜想。

先给出一个奇数 n n n,要求输出 3 3 3 个质数,这 3 3 3 个质数之和等于输入的奇数。

输入格式

仅有一行,包含一个正奇数 n n n,其中 9 < n < 20000 9 < n < 20000 9<n<20000

输出格式

仅有一行,输出 3 3 3 个质数,这 3 3 3 个质数之和等于输入的奇数。相邻两个质数之间用一个空格隔开,最后一个质数后面没有空格。如果表示方法不唯一,请输出第一个质数最小的方案,如果第一个质数最小的方案不唯一,请输出第一个质数最小的同时,第二个质数最小的方案。

样例 #1

样例输入 #1

2009

样例输出 #1

3 3 2003
#include <bits/stdc++.h>
using namespace std;
/*
先筛出范围内所有的质数
再对质数进行深搜
水。。。
*/
const int N = 20005;

int n;
bool st[N];
int primes[N];
int cnt;
int path[4];
bool flag;

inline void get_primes()
{ //先筛出数据范围内所有质数
    for(int i = 2; i <= N; i ++) {
        if(!st[i]) primes[++ cnt] = i;
        for(int j = 1; primes[j] * i <= N; j ++) {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0) break;
        }
    }
}

inline void dfs(int d, int r, int sum)
{ //d为搜索深度,r为质数次序,sum为当前总和

    if(flag) return;

    if(d > 3 && sum == n) {
        int t = 0;
        for(int i = 1; i <= 3; i ++) {
            cout << path[i];
            if(i != 3) cout << ' ';
        }
        flag = 1;
        return;
    }
    else if(d > 3 && sum != n) return;

    for(int i = r; i <= cnt; i ++) {
        if(sum + primes[i] <= n) {
            path[d] = primes[i];
            dfs(d + 1, i, sum + primes[i]);
            path[d] = 0;
        }
        else break;
    }

}
int main()
{
    cin >> n;
    get_primes();

    dfs(1, 1, 0);

    return 0;
}

斐波那契数列(升级版)

题目背景

大家都知道,斐波那契数列是满足如下性质的一个数列:

  • f ( 1 ) = 1 f(1) = 1 f(1)=1
  • f ( 2 ) = 1 f(2) = 1 f(2)=1
  • f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n-1) + f(n-2) f(n)=f(n1)+f(n2) n > 2 n > 2 n>2 n n n 为整数)。

题目描述

请你求出第 n n n 个斐波那契数列的数   m o d    2 31 \bmod\,2^{31} mod231 之后的值,并把它分解质因数。

输入格式

输入一个正整数 n n n

输出格式

把第 n n n 个斐波那契数列的数分解质因数。

样例 #1

样例输入 #1

5

样例输出 #1

5=5

样例 #2

样例输入 #2

6

样例输出 #2

8=2*2*2

提示

n ≤ 48 n \le 48 n48

感谢我的高中同学ht 不然我可能一直会用递归来求斐波那契
但实际上用for循环遍历一遍即可

#include <bits/stdc++.h>
using namespace std;
/*
用dfs来求斐波那契太慢了
是真的慢炸了我以为IDE坏了。。
改成for循环求斐波那契
*/
typedef long long LL;

const LL mod = pow(2, 31);

int n;
LL num[50];
queue<int> q;

LL get_num(int x)
{
    for(int i = 1; i <= x; i ++) {
        if(i == 1 || i == 2) num[i] = 1;
        else num[i] = num[i - 1] + num[i - 2];
    }

    return num[x];
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> n;
    LL t = get_num(n) % mod;

    cout << t << '=';
    for(LL i = 2; i * i <= t; i ++) {
        while(t % i == 0) t /= i, q.push(i);
    }

    if(t != 1) q.push(t);
    cout << q.front();
    q.pop();

    while(q.size()) {
        cout << '*' << q.front();
        q.pop();
    }

    return 0;
}

A+B Problem(再升级)

题目背景

题目名称是吸引你点进来的。

实际上该题还是很水的。

题目描述

  • 1 + 1 = ? 1+1=? 1+1=? 显然是 2 2 2
  • a + b = ? a+b=? a+b=? P1001 回看不谢。
  • 哥德巴赫猜想 似乎已呈泛滥趋势。

以上纯属个人吐槽

给定一个正整数 n n n,求将其分解成若干个素数之和的方案总数。

输入格式

一行一个正整数 n n n

输出格式

一行一个整数表示方案总数。

样例 #1

样例输入 #1

7

样例输出 #1

3

样例 #2

样例输入 #2

20

样例输出 #2

26

提示

样例解释

存在如下三种方案:

  • 7 = 7 7=7 7=7
  • 7 = 2 + 5 7=2+5 7=2+5
  • 7 = 2 + 2 + 3 7=2+2+3 7=2+2+3

数据范围及约定

  • 对于 30 % 30\% 30% 的数据 1 ≤ n ≤ 10 1\le n\le 10 1n10
  • 对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 3 1\le n\le 10^3 1n103

ycy同学,看到这里的时候请你去复习一下完全背包!

#include <bits/stdc++.h>
using namespace std;
/*
筛完质数
裸背包
爱切水题
补一句
是完全背包
然后我完全背包板子写错了
果然太久不做就忘光了
*/
typedef long long LL;

const int N = 1005;

int n;
LL f[N]; //f[i]为总和为 i 的方案数
int cnt, primes[N];
bool st[N];

void get_primes()
{
    for(int i = 2; i <= N; i ++) {
        if(!st[i]) primes[++ cnt] = i;
        for(int j = 1; primes[j] * i <= N; j ++) {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0) break;
        }
    }
}


int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> n;
    get_primes();

    f[0] = 1;
    for(int i = 1; i <= cnt; i ++) {
        for(int j = primes[i]; j <= n; j ++) {
            f[j] += f[j - primes[i]];
        }
    } 

    cout << f[n];

    return 0;
}

[AHOI2001]质数和分解

题目描述

任何大于 1 1 1 的自然数 n n n 都可以写成若干个大于等于 2 2 2 且小于等于 n n n 的质数之和表达式(包括只有一个数构成的和表达式的情况),并且可能有不止一种质数和的形式。例如, 9 9 9 的质数和表达式就有四种本质不同的形式:

9 = 2 + 5 + 2 = 2 + 3 + 2 + 2 = 3 + 3 + 3 = 2 + 7 9 = 2 + 5 + 2 = 2 + 3 + 2 + 2 = 3 + 3 + 3 = 2 + 7 9=2+5+2=2+3+2+2=3+3+3=2+7

这里所谓两个本质相同的表达式是指可以通过交换其中一个表达式中参加和运算的各个数的位置而直接得到另一个表达式。

试编程求解自然数 n n n 可以写成多少种本质不同的质数和表达式。

输入格式

文件中的每一行存放一个自然数 n ( 2 ≤ n ≤ 200 ) n(2 \leq n \leq 200) n(2n200)

输出格式

依次输出每一个自然数 n n n 的本质不同的质数和表达式的数目。

样例 #1

样例输入 #1

2
200

样例输出 #1

1
9845164
#include <bits/stdc++.h>
using namespace std;
/*
这升级版也不太行嘛!
不就是求一次改成了求好多次吗
*/
typedef long long LL;

const int N = 205;

int n;
LL f[N]; //f[i]为总和为 i 的方案数
int cnt, primes[N];
bool st[N];

void get_primes()
{
    for(int i = 2; i <= N; i ++) {
        if(!st[i]) primes[++ cnt] = i;
        for(int j = 1; primes[j] * i <= N; j ++) {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0) break;
        }
    }
}

LL amount(int n)
{
    memset(f, 0, sizeof f);

    f[0] = 1;
    for(int i = 1; i <= cnt; i ++) {
        for(int j = primes[i]; j <= n; j ++) {
            f[j] += f[j - primes[i]];
        }
    } 

    return f[n];
}


int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    get_primes();
    while(cin >> n)
    {
        cout << amount(n) << endl;
    }
    

    return 0;
}

Divided Prime

题目描述

给定一个数字 A A A,这个 A A A a 1 , a 2 , ⋯   , a N a_1,a_2,\cdots,a_N a1,a2,,aN相乘得到。

给定一个数字 B B B,这个 B B B b 1 , b 2 , ⋯   , b M b_1,b_2,\cdots,b_M b1,b2,,bM相乘得到。

如果 A B \frac{A}{B} BA是一个质数,请输出YES,否则输出NO

输入格式

每个测试点包含多组数据,第一行读入一个整数 T T T 表示数据组数,对于每组数据:

第一行输入两个整数 N , M N,M N,M,分别表示 A A A N N N 个数字相乘得到, B B B M M M 个数字相乘得到。

第二行输入 N N N 个整数,分别表示组成 A A A N N N 个数字。

第三行输入 M M M 个整数,分别表示组成 B B B M M M 个数字。

保证对于一个数字,其在 b i {b_i} bi 中出现的次数不多于在 a i {a_i} ai 中出现的次数。

输出格式

对于每组数据:
如果 A B \frac{A}{B} BA 是一个质数,请输出 YES,否则输出 NO
在输出 YESNO 后输出一个换行符。

样例 #1

样例输入 #1

2
3 2
5 7 7
5 7
4 2
5 7 7 7
5 7

样例输出 #1

YES
NO

提示

1 ≤ N ≤ 100000 1 \le N \le 100000 1N100000

0 ≤ M ≤ N 0 \le M \le N 0MN

1 ≤ a i , b i ≤ 1 0 12 1 \le a_i,b_i \le 10^{12} 1ai,bi1012

1 ≤ T ≤ 10 1 \le T \le 10 1T10

∑ N ≤ 100000 \sum N \le 100000 N100000

#include <bits/stdc++.h>
using namespace std;
/*
由题知
在分母中出现的数
一定在分子中出现过
而且分子中出现数量更多
所以只要把分子的数记录下来
再根据分母进行删除
最后乘起来判断即可
不过这种方法太暴力
效率不够好

其实在约掉一些数之后
剩下的数字
如果数量仍在2个以上
则肯定会形成合数
所以最多保留一个数字
然后再判断留下的这个数字是不是质数
要记住1不是质数!
*/
typedef long long LL;

int T, N, M;

bool check(vector<int> v, map<int, int> mp)
{//要注意1不是质数
    vector<int> t;
    for(int i = 0; i < v.size(); i ++) {
        if(mp[v[i]] >= 2) return false;
        else if(mp[v[i]] == 1 && v[i] != 1) t.push_back(v[i]);
    }
    
    if(t.size() != 1) return false;
    else {
        for(int i = 2; i <= t[0] / 2; i ++) {
            if(t[0] % i == 0) return false;
        }
        return true;
    }
}

int main()
{
    cin >> T;

    while(T --) {
        vector<int> v;
        map<int, int> mp;
        cin >> N >> M;

        for(int i = 1; i <= N; i ++) {
            LL a;
            cin >> a;
            if(mp.count(a)) {
                mp[a] ++;
            }
            else {
                mp[a] = 1;
                v.push_back(a);
            }
        }

        for(int i = 1; i <= M; i ++) {
            LL a;
            cin >> a;
            mp[a] --;
        }

        if(check(v, mp)) cout << "YES";
        else cout << "NO";

        if(T) cout << '\n';
    }

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
孪生素数是指两个素数之间的差值为2的素数对。通过筛选法可以找出给定素数范围内的所有孪生素数的组数。 在引用的代码中,使用了递归筛选法来解决孪生素数问题。该程序首先使用循环将素数的倍数标记为非素数,然后再遍历素数数组,找出相邻素数之间差值为2的素数对,并统计总数。 具体实现过程如下: 1. 定义一个数组a[N,用来标记数字是否为素数,其中N为素数范围的上限。 2. 初始化数组a,将0和1标记为非素数。 3. 输入要查询的孪生素数的个数n。 4. 循环n次,每次读入一个要查询的素数范围num。 5. 使用两层循环,外层循环从2遍历到num/2,内层循环从i的平方开始,将素数的倍数标记为非素数。 6. 再次循环遍历素数数组,找出相邻素数之间差值为2的素数对,并统计总数。 7. 输出总数。 至此,我们可以使用这个筛选法的程序来解决孪生素数问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python用递归筛选法求N以内的孪生质数(孪生素数)](https://blog.csdn.net/weixin_39734646/article/details/110990629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [NYOJ-26 孪生素数问题](https://blog.csdn.net/memoryofyck/article/details/52059096)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silver_Bullet14

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值