2022牛客寒假1 牛牛做数论(找规律)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

联系之前学过的 欧拉函数 φ(x),我们将函数 φ(x) 变一下形,令 H(x) = φ(x) / x

之后题目要求输入 n,并在 区间 [2, n] 中找到 H(x) 取最小值横坐标 x0(若 有多个最小值取最小的 x0),

区间 [2, n] 中找到 H(x) 取最大值横坐标 x0(若 有多个最大值取最大的 x0)。

思路:

先说 本题答案的结论 是:

问题一的答案2、2 × 3、2 × 3 × 5、2 × 3 × 5 × 7.…. 这些前若干个素数的积中,最大的且不超过 n 的那一个,如 n = 233,则答案为 2 × 3 × 5 × 7 = 210

问题二的答案[2, n] 中最大的素数。

如果 n 1直接输出 -1

实现细节:

对问题一,因为 很少 的一些 素数前缀积 就会超过 10 ^ 9 了因此 预处理出前几十个素数即可小心溢出

对问题二,从 n 开始 依次递减地暴力判断 是否为 素数 即可,这是因为 10 ^ 9 以内最大的两个素数间隔是 282,所以这样做 最多只要判断 282 个数字,且判断时往往 达不到根号的复杂度

问题一:由于
在这里插入图片描述
之中 pi 取遍 x所有种类的质因子(注意是 种类不是个数,如:素因子 2 出现两次 在公式里也只 乘上一次),则

在这里插入图片描述
显然 乘的项数越多每一项越小H(x) 就越小,按照 2、3、5、7、11..... 的顺序取 pi 就可以 达到这一目标

问题二:对于 素数 p
在这里插入图片描述
因此
在这里插入图片描述
直觉可以感到这是挺大的数(毕竟 H(x) 最大不超过 1),猜测取 最大的素数 p 即可。

这种题适合于 打表,所以我们也可以通过 打表 的方式来观察输出的结果,猜测它们 满足什么样的规律。

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 110;
int primes[N];
int cnt;
int n;
typedef vector<int> vi;
#define pb push_back
#define pp pop_back
vi pre_pro;

bool jud(int x) //判断是否为素数
{
    if(x<2) return false;
    for(int i=2; i<=x/i; ++i)
    {
        if(x%i==0) return false;
    }
    return true;
}

void init() //预处理1~N中的所有素数
{
    for(int i=2; i<N; ++i) 
    {
        if(jud(i))
        {
            primes[cnt++] = i;
        }
    }
}

void prefix_pro() //预处理素数前缀积
{
    pre_pro.pb(1);
    for(int i=1; i<=cnt; ++i)
    {
        int t = pre_pro[i-1] * primes[i-1];
        pre_pro.pb(t);
        if(t>9699690) break;
    }
}

int main()
{
    init();
    prefix_pro();

    int t; cin>>t;
    while(t--)
    {
        int n; cin>>n;
        if(n==1) puts("-1");
        else
        {
            int mnpos;
            for(int i=1; i<pre_pro.size(); ++i)
            {
                int v = pre_pro[i];
                if(v<=n) mnpos = v;
            }
            cout<<mnpos<<' ';

            int mxpos;
            for(int i=n; i>=2; --i)
            {
                    if(jud(i)) 
                    {
                        mxpos = i; 
                        break;
                    }
            }
            cout<<mxpos<<'\n';
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值