Coding Practice,48天强训(32)

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;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值