OPPO提前批笔试 B卷

第一题 不小于X的最小素数

题解

#include <iostream>
using namespace std;
/*
    不小于x的最小素数
*/

bool isprime(long long n)
{
    if (n <= 1)
        return false;

    if (n == 2 || n == 3)
        return true;

    if (n % 6 != 1 && n % 6 != 5)
        return false;

    for (int i = 5; i * i <= n; i++)
    {
        if (n % i == 0)
            return false;
    }

    return true;
}

int main()
{
    long long x;
    cin >> x;
    if (x == 1 || x == 2)
    {
        cout << 2 << endl;
        return 0;
    }

    if (x == 3)
    {
        cout << 3 << endl;
        return 0;
    }
    if (x == 4 || x == 5)
    {
        cout << 5 << endl;
        return 0;
    }

    long long n = x / 6 - 2;
    long long number1, number2;
    while (n)
    {
        number1 = 6 * n - 1;
        if (number1 >= x && isprime(number1))
        {
            cout << number1 << endl;
            break;
        }

        number2 = 6 * n + 1;
        if (number2 >= x && isprime(number2))
        {
            cout << number2 << endl;
            break;
        }
    }
}
// 64 位输出请用 printf("%lld")

这个题的加速方法就是:一个数是素数,则其必然为6n-1或者6n+1(除2和3外)

第二题 随机删除一个元素使得奇偶位元素和差异最小

题目描述

一个长为n的正整数数组,现随机从数组中删除一个数,求删除后数组奇数位和与偶数位和的绝对值的最小值。(奇偶位置为删除以后的数组)。

解题思路

维护原数组中奇数位和偶数位的前缀和,那么在 i 元素被删除以后

删除后数组奇数位的和为:i 前面 奇数和 + i 后面偶数位和。

删除后数组偶数位的和为:i 前面 偶数和 + i 后面奇数位和。

更新 | 奇数和 - 偶数和 | 的最小值即可。

题解

#include <iostream>
#include <vector>
using namespace std;

/*

一个长为n的正整数数组,现随机从数组中删除一个数,求删除后数组奇数位和与偶数位和的绝对值的最小值
(这个题解没有验证过,事后做的题目)

*/

int main()
{
    int n;
    cin >> n;
    // n = 7;
    vector<int> nums(n + 1, 0);
    for (int i = 1; i <= n; i++)
        cin >> nums[i];
    // vector<int> nums{0, 1, 2, 3, 4, 5, 6, 7};

    // nums valid idx from 1 to n both close
    vector<int> preSumOdd(n + 2, 0), preSumEven(n + 2, 0);
    int evenStart = 0, oddStart = 0;
    for (int i = 1; i <= n; i++)
    {
        if (i % 2 == 1) // odd number
        {
            if (i == 1)
                preSumOdd[i] = nums[i];
            else
                preSumOdd[i] = preSumOdd[i - 2] + nums[i];

            preSumEven[i] = preSumEven[i - 1];
        }
        else // even bumber
        {
            if (i == 2)
                preSumEven[i] = nums[i];
            else
                preSumEven[i] = preSumEven[i - 2] + nums[i];

            preSumOdd[i] = preSumOdd[i - 1];
        }
    }

    // cout << "odd pre sum" << endl;
    // for (auto odd : preSumOdd)
    //     cout << odd << " ";
    // cout << endl;
    // cout << "odd pre sum" << endl;
    // for (auto even : preSumEven)
    //     cout << even << " ";
    // cout << endl;

    int minAbsDiff = INT_MAX;
    int deleteIdx = -1;
    for (int delIdx = 1; delIdx <= n; delIdx++)
    {
        int frontOddSum = preSumOdd[delIdx - 1];
        int frontEvenSum = preSumEven[delIdx - 1];
        int backOddSum = preSumOdd[n] - preSumOdd[delIdx];
        int backEvenSum = preSumEven[n] - preSumEven[delIdx];

        // cout << "deleted element at idx: " << delIdx << " frontOddSum: " << frontOddSum << " frontEvenSum: " << frontEvenSum << " backOddSum: " << backOddSum << " backEvenSum:" << backEvenSum << endl;

        int sum1 = frontEvenSum + backOddSum;
        int sum2 = frontOddSum + backEvenSum;
        if (abs(sum1 - sum2) < minAbsDiff)
        {
            minAbsDiff = abs(sum1 - sum2);
            deleteIdx = delIdx;
        }
    }

    cout << " minAbsDiff: " << minAbsDiff << " deleteIdx: " << deleteIdx << endl;
    return 0;
}

第三题 字符串拆解为可以被两个整数整除的子串

题目描述

给一个字符串str(最长为1e5个字符)和两个int类整数x和y;

请把str拆成str1和str2,使得str1组成的数字能被x整除,str2组成的数字能被y整除(如果有多个解,任意一个即可);

如果找到不,输出-1。

解题思路

使用一个cur指针从前往后遍历str,对于左边str1,维护一个XYu(int类型即可)表示[0,cur]区间内字符串组成的数字对x的余数,如果xYu为0,表示从[0,cur]区间内字符串可以被x整除;当可以整除时,判断[cur+1,str.length()-1]子串会否可以被y整除。

其实这个题目就是一个大数除法的简化版。

题解

#include <iostream>
#include <string>
using namespace std;

/*
    给一个字符串str(最长为1e5)和两个int类整数x和y;
    请把str拆成str1和str2,使得str1组成的数字能被x整除,str2组成的数字能被y整除,如果找到不,输出-1。
*/

bool canBeDevided(const string s, int startIdx, int endIdx, const int devider)
{
    int Yu = 0;
    int cur = startIdx;
    for (cur; cur <= endIdx; cur++)
    {
        Yu = Yu * 10 + int(s[cur] - '0');
        Yu %= devider;
    }

    if (Yu == 0)
        return true;
    else
        return false;
}

int main()
{

    // cout << canBeDevided("135", 0, 2, 5);
    // cout << canBeDevided("135", 0, 1, 5);

    string str;
    cin >> str;
    int x, y;
    cin >> x >> y;

    int xYu = 0;
    int cur = 0; // [0,cur] [cur+1,lenght+1]

    bool find = false;

    for (cur; cur + 1 <= str.length() - 1; cur++)
    {
        xYu = xYu * 10 + (int)(str[cur] - '0');
        if (xYu < x)
            continue;
        else
        {
            if (xYu % x == 0)
            {
                if (canBeDevided(str, cur + 1, str.length() - 1, y))
                {
                    cout << str.substr(0, cur + 1) << " " << str.substr(cur + 1) << endl;
                    find = true;
                    break;
                }
            }
            else
            {
                xYu %= x;
            }
        }
    }

    if (!find)
        cout << -1 << endl;

    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值