百度松果菁英班OJ【连载】

2022-10-29,

第十六周

2 的 n 次幂

高精度乘法

#include<bits/stdc++.h> 

using namespace std;

vector<int> mul(vector<int> &A) {
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i++) {
if (i < A.size()) t += A[i] * 2;
C.push_back(t % 10);
t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
} int main()
{
int n;
cin >> n;
vector<int> A;
A.push_back(1);
while (n--) {
A = mul(A);
}
for (int i = A.size() - 1; i >= 0; i--) {
printf("%d", A[i]);
}
return 0;
}

个数统计

高精度乘法求阶乘
个数统计

#include<bits/stdc++.h> 

using namespace std;

vector<int> mul(vector<int> &A, int x) {
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i++) {
if (i < A.size()) t += A[i] * x;
C.push_back(t % 10);
t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
} int main( )
{
int N, a;
cin >> N >> a;
vector<int> A;
A.push_back(1);
for (int i = 2; i <= N; i++) {
A = mul(A, i);
}
int ans = 0;
for (int i = A.size() - 1; i >= 0; i--) {
if (A[i] == a) ans++;
}
cout << ans << endl;
return 0;
}

数组扞插

题目复述:

将数组分为三部分,前半段,后半段,和中间的数(如果数组大小是奇数)
前半段升序排列
后半段降序排列
如果有中间的数字,则中间的数不参与排列,直接放到结果数组的末尾

#include<bits/stdc++.h> 

using namespace std;

int n;
const int N = 10010;
int a[N], b[N]; int main( )
{
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int l = n + 1 >> 1; // 前半段 + 中间数字(可能没有)
int r = n - l; // 后半段
if (l == r) { // 前后一样多
sort(a, a + l, less<int>());
sort(a + l, a + n, greater<int>());
}
else { // 前面多一个,则中间的数不参与排序
sort(a, a + l - 1, less<int>());
sort(a + l, a + n, greater<int>());
}
int ll = 0, rr = l; // 交叉插入结果数组
for (int i = 0; i < n; i++) {
if (i % 2 == 0) b[i] = a[ll++];
else b[i] = a[rr++];
}
for (int k = 0; k < n; k++) {
printf("%d ", b[k]);
}
return 0;
}

MXR 竞赛

题目复述:

N 个问题,都有积分,范围为负数、零和正数
选出所有一个积分子集,使得子集中的所有积分的乘积得到最大值

解法:

贪心思想
所有积分从小到大排序,所有正数全部参与乘积
所有负数,相邻两个负数相乘得到正数。从左向右遍历,只要相邻两个积分是负数,则这两个负数都参与乘积;最后可能剩下一个绝对值最小的负数,不参与乘积
特殊情况:如果所有积分都没有选取,比如只有一个负数,返回数组最后一个数(最大)

#include<bits/stdc++.h> 

using namespace std;

const int N = 100010;
long n;
int a[N]; int main( )
{
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
long ans = 1; // 注意精度,int 会爆精度
int flag = 0;
sort(a, a + n);
for (int i = 0; i < n; i++) {
if (a[i] < 0) {
if (i < n - 1 && a[i + 1] < 0) {
ans = ans * (a[i] * a[i + 1]);
ans %= 998244353;
i++;
flag++;
}
} else if (a[i] > 0) {
ans = ans * a[i];
ans %= 998244353;
flag++;
}
}
if (flag == 0) printf("%d", a[n - 1]);
else printf("%d", ans);
return 0;
}

小码哥的跳棋游戏

题目复述:

没有棋子不消耗能量
一次最多跳过一个棋子
破坏一个棋子消耗一个能量
求消耗最小能量从 0 位置到达 n 位置

解法:

贪心思想 + 双指针
对于连续 n 个棋子,n 为奇数,最少破坏 ⌊n / 2⌋ 个棋子
对于连续 n 个棋子,n 为偶数,最少破坏 n / 2 个棋子
由于 int 除法自动取整特性,以上两种情况可以合并

#include<bits/stdc++.h> 

using namespace std;

const int N = 100010;
int a[N]; int main( )
{
int n;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int ans = 0;
int i = 0;
while (i < n) {
// 出现棋子
if (a[i] == 1) {
int count = 1;
int j;
// 统计连续棋子个数
for (j = i + 1; j < n && a[j] == 1; j++) {
count++;
}
ans += count / 2;
// 破坏之后就可以跳动了
i = j;
} else {
// 没有棋子就直接跳
i++;
}
}
// 由于跳动到第 n 块,如果第 n - 1 块是棋子,需要破坏
if (a[n - 1] == 1) ans++;
cout << ans;
return 0;
}

矩阵乘法

常规矩阵乘法

#include<bits/stdc++.h> 

using namespace std;

const int N = 1010;
int a[N][N], b[N][N], c[N][N];
int l, m, n;
void mul(int a[][N], int b[][N]) {
for (int i = 0; i < l; i++) {
for (int j = 0; j < n; j++) {
for (int k =0; k < m; k++) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
} int main( )
{
cin >> l >> m >> n;
for (int i = 0; i < l; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &a[i][j]);
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &b[i][j]);
}
}
mul(a, b);
for (int i = 0; i < l; i++) {
for (int j = 0; j < n; j++) {
printf("%d ", c[i][j]);
}
printf("\n");
}
return 0;
}

百度松果菁英班OJ【连载】的相关教程结束。

《百度松果菁英班OJ【连载】.doc》

下载本文的Word格式文档,以方便收藏与打印。