Topic 1:素数回文

更贴近应用层,考察一些基础知识点,当复习很不错
#include <bits/stdc++.h>
using namespace std;
// 判断是否为素数
bool is_prime(long long n)
{
if (n <= 1) return false;
if (n == 2 || n == 3) return true;
if (n % 2 == 0 || n % 3 == 0) return false;
for (long long i = 5; i * i <= n; i += 6)
{
if (n % i == 0 || n % (i + 2) == 0) return false;
}
return true;
}
// 构造题目定义的“回文数”
long long cp(int t)
{
string s = to_string(t);// to_string(t)用于将数字转换为字符串
string rev = s;
reverse(rev.begin(), rev.end());// 反转函数
rev.erase(0, 1); // 去掉开头一位,避免重复中间数 17 = 171 而不是1771
string result = s + rev;
return stoll(result); // 转成 long long
}
int main()
{
int t; cin >> t;
long long pd = cp(t);
if (is_prime(pd)) cout << "prime" << endl;
else cout << "noprime" << endl;
return 0;
}
把轮子的底层贴出来,方便复习
#include <iostream>
using namespace std;
// 判断是否为素数
bool is_prime(long long n)
{
if (n <= 1) return false;
if (n == 2 || n == 3) return true;
if (n % 2 == 0 || n % 3 == 0) return false;
for (long long i = 5; i * i <= n; i += 6)
{
if (n % i == 0 || n % (i + 2) == 0) return false;
}
return true;
}
// 手写:整数转字符串(类似 to_string)
string my_to_string(int t)
{
// 特殊情况:如果数字是 0,直接返回字符串 "0"
if (t == 0) return "0";
string res; // 用来保存转换后的字符串
bool negative = false; // 判断是否为负数
// 如果数字是负数,记录下来并转换成正数处理
if (t < 0)
{
negative = true; // 标记为负数
t = -t; // 将负数转为正数(方便后续处理)
}
// 将数字按位分解,转换成字符并追加到结果字符串
while (t > 0)
{
// 取当前数字的最后一位,并将其转换为字符('0' 的 ASCII 码是 48)
char digit = (t % 10) + '0';
res += digit; // 将字符追加到结果字符串
t /= 10; // 去掉最后一位数字,继续处理剩余部分
}
// 如果原始数字是负数,在字符串末尾添加负号
if (negative) res += '-';
// 由于数字是反向存储的(个位在最前),需要反转字符串
int i = 0, j = res.length() - 1; // 使用两个指针从两端向中间扫描
while (i < j)
{
swap(res[i], res[j]); // 交换两个位置的字符
i++; // 左指针向右移动
j--; // 右指针向左移动
}
return res; // 返回反转后的字符串
}
// 手写:字符串反转(类似 reverse)
void my_reverse(string& s)
{
int i = 0, j = s.length() - 1; // 使用两个指针,左指针 i 从 0 开始,右指针 j 从字符串末尾开始
while (i < j)
{
swap(s[i], s[j]); // 交换 i 和 j 指向的字符
i++; // 左指针向右移动
j--; // 右指针向左移动
}
}
// 手写:删除字符串第一个字符(类似 erase(0, 1))
void my_erase_first_char(string& s)
{
// 从索引 1 开始,将每个字符左移一位
for (int i = 1; i < s.length(); ++i)
{
s[i - 1] = s[i]; // 左移字符
}
s.pop_back(); // 删除最后一个字符(由于左移了,所以原始的第一个字符已经移除)
}
// 手写:字符串转 long long(类似 stoll)
long long my_stoll(const string& s)
{
long long res = 0; // 初始化结果为 0
// 遍历字符串中的每个字符,逐个转换为数字并累加到结果中
for (char c : s)
{
res = res * 10 + (c - '0'); // 将字符转换为数字并加到结果中
}
return res; // 返回转换后的 long long 值
}
// 手写构造题目定义的“回文数”
long long cp(int t)
{
string s = my_to_string(t); // 把数字 t 转为字符串
string rev = s; // 复制原字符串,用来反转
my_reverse(rev); // 反转 rev 字符串
my_erase_first_char(rev); // 删除 rev 的第一个字符(避免重复)
string result = s + rev; // 将原字符串和反转后的部分拼接起来,形成回文数
return my_stoll(result); // 将拼接后的字符串转换回 long long 类型并返回
}
int main()
{
int t; cin >> t;
long long pd = cp(t);
if (is_prime(pd)) cout << "prime" << endl;
else cout << "noprime" << endl;
return 0;
}
Topic 2:活动安排

#include <bits/stdc++.h>
using namespace std;
bool compare(pair<int, int> a, pair<int, int> b)
{
return a.second < b.second; // 按结束时间升序排
}
int main()
{
int n; cin >> n;
vector<pair<int, int>> act(n);
for (auto& a : act) cin >> a.first >> a.second;
sort(act.begin(), act.end(), compare); // 按结束时间排
int res = 1;// 可行活动数
int lt = act[0].second;// 上个活动的结束时间
for (int i = 1; i < n; i++)
{
if (act[i].first >= lt)
{
res++;
lt = act[i].second;
}
}
cout << res << endl;
return 0;
}
比较简单,先开始还准备用小根堆做,后来发现不用,模拟一下就行了
Topic 3:合唱团

网易的困难题,多做几遍
首先明确dp含义:
dpmax[i][j]表示以第 i 个学生结尾,选 j 个学生时的最大乘积
dpmin[i][j]表示以第 i 个学生结尾,选 j 个学生时的最小乘积
递推公式:
p 是一个范围在[i - d, i - 1]之间
dp_max[i][j] = max(dp_max[i][j], max(dp_max[p][j-1] * a[i], dp_min[p][j-1] * a[i]))
dp_max[i][j] = max(dp_max[p][j-1] * a[i], dp_min[p][j-1] * a[i])),后半段比较好理解,p是在[i - d, i - 1]之间,等于说是弄个循环,在里面找最大的p,去*a[i],然后找最小的p也去*a[i](看会不会负负得正),最后得到两个乘积,比较一下,大的那个就是dp_max[i][j],但是为啥外面还要和dp_max[i][j]比较一下呢?
因为这个p是要完成从i - d,到i - 1的遍历的,在p=i-d时,最后计算出的dp_max[i][j]是一个数,i-d+1又是一个,i-d+2又是一个,这种不断地比较会让所有可能性中最大的那个被选出来记录在dp_max[i][j]里,所以其实是这次的dp_max[i][j]在和上一个dp_max[i][j]比较,大的那个就会被存下来,下一次产生的dp_max[i][j]就再来比,最后最大的那个也就是最终的答案了
dp_min[i][j] = min(dp_min[i][j], min(dp_max[p][j-1] * a[i], dp_min[p][j-1] * a[i])),这个也是同理,只不过max换成min
#include <algorithm>
#include <bits/stdc++.h>
#include <climits>
using namespace std;
//几个处理要点
//数组中可能有负数,负数相乘会成为正数的,所以要同时考虑最大和最小值的情况-5*-5 > 4*5
//实际上数形结合一下,可以get到————最小值就是箭头往左走时的最大值
typedef long long ll;
void solve(int n, int k, int d, vector<int> a)
{
//明确dp含义
//dpmax[i][j]表示以第 i 个学生结尾,选 j 个学生时的最大乘积
//dpmin[i][j]表示以第 i 个学生结尾,选 j 个学生时的最小乘积
vector<vector<ll>> dpmax(n, vector<ll>(k + 1, 0));
vector<vector<ll>> dpmin(n, vector<ll>(k + 1, 0));
//递推公式 p 是一个范围在[i - d, i - 1]之间
//dpmax[i][j] = max(dpmax[i][j], max(dpmax[p][j-1] * a[i], dpmin[p][j-1] * a[i]))
//dpmin[i][j] = min(dpmin[i][j], min(dpmax[p][j-1] * a[i], dpmin[p][j-1] * a[i]))
//初始化,选0个人时结果是0,在最开始的数组初始化处已经完成了,全初始化为0
//当只选1个人是,也就是dp[i][j] j = 1的情况,max min都是自己
for(int i = 0; i < n; ++i)
{
dpmax[i][1] = a[i];
dpmin[i][1] = a[i];
}
ll res = LLONG_MIN; //记录答案
//循环顺序,三层循环,最外层遍历选择学生的个数,从2(0,1已经初始化过了)到k
//中层遍历所有学生,以i结尾
//内层遍历i的选择p,p从i - d 到 i - 1,如果i-d<0则从0开始
for(int j = 2; j <= k; ++j)
{
for(int i = 0; i < n; ++i)
{
for(int p = max(0, i - d); p < i; ++p)
{
dpmax[i][j] = max(dpmax[i][j], max(dpmax[p][j-1] * a[i], dpmin[p][j-1] * a[i]));
dpmin[i][j] = min(dpmin[i][j], min(dpmax[p][j-1] * a[i], dpmin[p][j-1] * a[i]));
}
}
}
// 答案是所有 dpmax[i][k] 中的最大值
for(int i = k - 1; i < n; ++i) res = max(res, dpmax[i][k]);
//i从k-1开始省略一些无意义的值,毕竟你如果要选7个数的乘积,那么结尾数在12345之类的就结束了能有多大呢
cout << res << endl;
}
int main()
{
int n, k, d; cin >> n;
vector<int> a(n);
for(auto& i : a) cin >> i;
cin >> k >> d;
solve(n, k, d, a);//总共n 个学生; 选取 k 名学生; 相邻下标差不能超过 d;
return 0;
}
4671

被折叠的 条评论
为什么被折叠?



