第一题 不小于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;
}