2025牛客寒假算法基础集训营1补题:ABDGH

A题:茕茕孑立之影

补充:数据类型及其范围

1. char 

        有符号char: -128到127, 大致为 -10^{2} 到 10^{2}; 无符号char:0到255, 大致为0 到 10^{2}

2. int

        有符号int:-2147483648 到 2147483647 , 大致为-10^{9 } 到 10^{9}

        无符号int:0 到 4294967295,大致为0 到 10^{10}

3.long

        有符号long: 大致为-10^{19} 到 10^{19}; 无符号long: 0 到 10^{20}

4.long long 

        有符号long long:大致为-10^{19} 到 10^{19};无符号long: 0 到 10^{20}

5.float

        大致为-3.4*10^{38 } 到  3.4*10^{38}

6.double

        大致为-1.7*10^{308} 到 1.7*10^{308}

思路:

        判断数组是否有 1,因为 1 是所有数字的因数,如果有,输出-1;如果没有,找到范围内最大的质数。题目所给的整数范围是10^{9},故找到一个更大的质数是 1e9+7 

代码:

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

int main(){
    int res = 1e9 + 7;
    int count , k  ;//分别是 组数, 该组数的个数
    //输入组数
    cin >> count;
    for(int i = 0; i < count ; i++)
    {
        //记录输入的一组数的个数
        cin >> k;
        //记录数组
        vector<int> num(k); //分配好k个空间,就不会出现数组越界的问题
        bool flag = false;
        int max = 0;
        for(int j = 0; j < k ;j++){
            cin >> num[j];
            if(num[j] == 1){
                flag = true;
            }
        }
        
        if(flag){
           cout<<"-1"<<endl;
        }else{
            cout<<res<<endl;
        } 

    }
    return 0;
}

B题:一气贯通之刃

思路:

        建立一个数组,每个位置则对应一个节点,记录输入路径,在对应位置++,即在位置上记录节点度数。遍历数组,寻找度为1的节点,也就是叶子节点。如果叶子节点超过2个,无法构成简单路径,输出-1; 否则,输出两个叶子节点

代码:

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

int main() {
    int n;
    cin >> n;

    vector<int> degree(n + 1, 0); //定义一个数组,大小为n+1,初始化为0

    //记录输入的路径
    //每个位置对应一个节点
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        degree[u]++;      //在对应位置++,即 度数 的改变
        degree[v]++;
    }

    // 寻找度为 1 的节点,也就是叶子节点
    vector<int> leaf;
    for (int i = 1; i <= n; ++i) {
        if (degree[i] == 1) {
            leaf.push_back(i);
        }
    }

    // 如果叶子节点超过 2 个,则无法构成简单路径
    if (leaf.size() != 2) {
        cout << -1 << endl;
    }
    else {
        // 输出两个叶子节点
        cout << leaf[0] << " " << leaf[1] << endl;
    }

    return 0;
}

D题:双生双宿之决

思路:

        对于每个数组: 1. 判断个数是否为偶数,否:输出No;2.用unordered_map存储数组,判断是否只有两种键; 3.继续判断每种元素的个数是否相同,通过三个检测,输出Yes;最外层添加一个不符合条件的检测

代码:

#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;
void ifTwin(pair<int, vector<int>> test)
{
    //判断个数是否为偶数
    int num = test.first;
    if(num % 2 != 0)
    {
        cout<< "No"<<endl;
        return;
    }
    
    //个数是偶数,接下来统计是否只有两种键
    //先把数组存下来
    vector<int> arr = test.second;
    unordered_map<int, int> maps;
    for(int a : arr)
    {
        maps[a]++;
    }
    
    if(maps.size() == 2)
    {
        auto it = maps.begin();
        int count1 = it->second;
        ++it;
        if(count1 == num / 2)
        {
            cout << "Yes" << endl;
            return;
        }
    }
    
    //不符合条件
    cout << "No" << endl;
}

int main()
{
    int count;
    cin >> count;
    while(count--)
    {
        int n; //单个数组的大小
        cin>> n;
        pair<int, vector<int>> test; //存储数组 个数 和 数组内容
        vector<int> a(n); //数组内容
        for(int i = 0; i < n; i++)
        {
            cin >> a[i];
        }
        test = make_pair(n, a); //填充pair
        //判断是否是双生数组
        ifTwin(test);
    }
    return 0;
}

补充:pair知识点 & map知识点(unordered_map & order_map )

pair知识点总结

pair是一个模板类,用于将两个不同类型的值组合成一个单元

pair< int, double > p1;  //默认初始化:int 为0, double 为0.0 

make_pair(20, 2.91);   //使用make_pair,可以根据传入的参数自动推导类型

p1.first  ;   p1.second;  //分别访问第一第二个元素

map知识点总结 

        map基于红黑树(自平衡的二叉搜索树)实现,存储元素的键值对,且键是唯一的,元素会按照键的升序自动排序

头文件: <map>

map< int , string > myMap;                  //空map

myMap.insert(make_pair(4, "four") );   //使用insert函数插入元素

myMap[5] = "five";                                //使用[ ]操作符,如果键不存在,会插入新的键值对;如果已存在,会更新对应的值

查找元素:find函数

//使用find函数: 返回一个迭代器,如果找到则指向该元素,否则指向end( )
auto it = myMap.find(3);
if(it != myMap.end() ) {
    cout << "value of key 3:"  << it->second << endl;
}       

删除元素: erase函数

myMap.erase(3);        //根据键删除
auto it = myMap.find(3);
if(it != myMap.end() ) {
    myMap.erase(it); //根据迭代器删除
}

遍历元素:

for( const auto& pair : myMap ) {
    cout << "Key:" << pair.first << ", Value" << pair.second << endl;
}

unordered_map知识点总结 

        unordered_map,基于哈希表实现,存储的元素是键值对,键是唯一的,但元素不会按照键的顺序排序,而是根据哈希值排序

头文件<unordered_map>

声明、定义、插入、访问、删除元素和map基本相同

 G题:井然有序之衡

思路:

        对于可以进行任意次操作的题目,要抓住不变的点,这题中为元素之和不变!元素和为排列的和,并且操作时,加1和减1的次数相同。

1.判断元素之和是否为排列和,否,输出-1;

2.将数组自小而大排列,计算对应位置要加/减的数,存在两个数中;

3.判断加和减的数是否相等,如果不等,输出-1, 如果相等,输出减/加其中一个即为操作数

【注意】:计算排列和时候设置的数据类型要为 long long,又因为乘积后的数据类型和原数据类型是一样的,所以代表元素数量的 num 的类型也要是long long

代码: 

#include<iostream>
#include<vector>
#include<algorithm>
//数的总和不会改变!!!

using namespace std;
int main()
{
    long long  num; //数组中元素的数量
    cin >> num ;
    vector<int> arr(num);
    long long sum;
    sum = ( (num + 1) * num ) /2; //乘积后的数据类型和原数据类型是一样的,所以num的类型也要是long long
    long long count = 0;
    for(int i = 0; i< num ;i++)
    {
        cin >> arr[i];
        count += arr[i];
    }
    if(count != sum)
    {
        cout<<"-1"<<endl;
    }
    else{
        sort(arr.begin() , arr.end());
        //计算对应位置要加/减的数,这两个数相等,就可以,并且就是最小次数
        long long plus = 0 , sub = 0 ;
        for(int i = 0; i< num ;i++)
        {
            
            if(arr[i] == i+1 )
            {
                continue;
            }
            else if(arr[i] > i+1)
            {
                sub += arr[i] - (i + 1);
            }
            else{
                plus += (i + 1) - arr[i];
            }
        }
        if(sub != plus)
        {
            cout<<"-1"<<endl;
        }
        else{
            cout<<plus<<endl;
        }
    }
    
    return 0;
}

H题:井然有序之窗

思路:

        1. 先将根据左界从小到大进行排序(存储n, r,l三个数)

                (1)用优先队列存放->可以存下当前数的区间【有效区间】

                (2)移除堆中所有右端点小于当前数字的区间

                (3)如果堆为空,输出-1;否则。取出堆顶区间,分配当前数字

代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

// 比较函数,先按左端点排序,左端点相同则按右端点排序
bool compare(const pair<pair<int, int>, int>& a, const pair<pair<int, int>, int>& b) {
    if (a.first.first == b.first.first) {
        return a.first.second < b.first.second;
    }
    return a.first.first < b.first.first;
}

int main() {
    int n;
    cin >> n;
    vector<pair<pair<int, int>, int>> range(n); // 存放左右范围和原始位置
    for (int i = 0; i < n; i++) {
        cin >> range[i].first.first >> range[i].first.second;
        range[i].second = i; // 记录原始位置
    }

    // 按左端点从小到大排序
    sort(range.begin(), range.end(), compare);

    // 小根堆,存储 {右端点, 原始位置}
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> valid;

    // 结果数组
    vector<int> res(n);
    // 标记数字是否已使用
    vector<bool> used(n + 1, false);

    int index = 0;
    for (int num = 1; num <= n; num++) {
        // 将左端点小于等于当前数字的区间加入堆中
        while (index < n && range[index].first.first <= num) {
            valid.push({range[index].first.second, range[index].second});
            index++;
        }

        // 移除堆中所有右端点小于当前数字的区间
        while (!valid.empty() && valid.top().first < num) {
            valid.pop();
        }

        // 如果堆为空,说明没有合适的区间可以分配当前数字
        if (valid.empty()) {
            cout << -1 << endl;
            return 0;
        }

        // 取出堆顶区间,分配当前数字
        int pos = valid.top().second;
        valid.pop();
        res[pos] = num;
        used[num] = true;
    }

    // 输出结果
    for (int i = 0; i < n; i++) {
        cout << res[i] << " ";
    }
    cout << endl;

    return 0;
}

补充:sort排序 & 小根堆知识点

sort排序:默认比较规则(升序)

头文件: <algorithm>

#include<iostream>
#include<vector>
#include<algorithm>

template<class T>
void sort( T first, T last );

int main() {
    vector<int> nums = {5, 2, 8, 1, 9};
    sort(nums.begin(), nums.end());    //升序
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;
    return 0;
}

自定义规则:自定义一个比较函数

#include <algorithm>
#include <vector>
#include <iostream>
//自定义比较函数,实现降序排序
bool compare(int a, int b){
    return a > b;
}
int main(){
    vector<int> nums = {5, 2, 6, 3 };
    sort(nums.begin(), nums.end(), compare); 
    for( int num : nums ){
        cout << num <<" ";
    }
    return 0;
}

        自定义类型排序,还可以使用lambda表达式; 可以实现对自定义类型的容器(如结构体等)排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值