SMU-ACM集训队2024 2nd


The Second Week

路漫漫其修远兮,吾将上下而求索 ————屈原

一、前言

周一打了场cf,晚上实在太困了打得很不好,也没打完,花点时间补题吧。周四整忘了直接开训练了,下次再来。
周二打了天梯模拟,反正二十分题及以下题全都做出来了,只做出了一题二十五分题,一个大二的都没打过呢。一些STL根本用不出来,纯暴力手写了。
周六成信大天梯赛,前七题八十分我简直无言以对,做题速度太慢,一直在修改,后来也没有时间看别的题目。当然也不会做。
周二天梯模拟,周六试了一下电子科大的校赛,微笑点头.jpg。这比赛都不知道有没有补题的必要了。


二、算法

1.STL

这几道题没什么难度,不用STL也能写出来,主要是熟悉一下stack,queue,vector之类的。不然总是用数组int,有点低级。当然主要是因为我比赛时一直没能过全部案例太可气了。

<1>(SMU 2024 spring 天梯赛1 7—8)

机工士姆斯塔迪奥 分数20
题解:
题意表达为输入构造一个n行m列的地图,q组数字t,c,t=1表示选择c行消失,t=0表示选择c列消失,计算最后留下来的格子。
本题考虑删除相同俩行的情况,采用set自动去重功能,注意set的插入和便利。运用数学思维先删除ls行个格子,再删去hs列格子即可。
代码:

#include<iostream>
#include<set>

using namespace std;
int main(){
    int n,m,q;
    cin>>n>>m>>q;
    set<int>h;
    set<int>l;
    for(int i=0;i<q;i++){
        int t,c;
        cin>>t>>c;
        if(t==1){
            l.insert(c);          //set的插入
        }
        if(t==0){
            h.insert(c);
        }
    }
    int sum=n*m;
    int ls=0,hs=0;
    for(auto i:l){               //set的遍历
        ls++;                    //计算l中元素数量
    }
    for(auto i:h){               //同上
        hs++;
    }
    sum-=(ls*n);
    sum-=(hs*(m-ls));
    cout<<sum<<endl;
}

<2>(SMU 2024 spring 天梯赛1 7—9)

彩虹瓶 分数25
题解:
题意为输入彩虹瓶数量n,容量m,k组判断样例,每组n个数字,要求按字母序取瓶子,如果存放的瓶子超过容量判断st为false,或者要取出非栈顶的元素也判定为false,然后按照st的状态输出即可。注释了一些导致我未ac的原因。
代码:

#include<iostream>
#include<stack>

using namespace std;

int n,k;
size_t m;
stack<int>box;
void solve(){
    int id=1;
    bool st=true;
    while(!box.empty()){
        box.pop();
    }                                              //清空栈
    for(int i=1;i<=n;i++){
        int ls;
        cin>>ls;
        box.push(ls);
        if(!box.empty()&&box.top()==id){
            //为什么要在这先判断一次呢,相当于如果现在手上的货物不用放在货架上
            //所以它的数量不会影响box.size()
            box.pop();
            id++;
        }
        if(box.size()>m){                          //超过货架的容量
            st=false;
        }
        while(!box.empty()&&box.top()==id){        //我的天这里因为循环条件的先后导致段错误
            box.pop();                             //先判断栈是否为空
            id++;                                  //尝试访问栈顶元素导致未定义行为就是段错误
        }
    }
    if(id!=n+1){                                   //因为最后拿出编号为n的货物后id还会加一
        st=false;
    }
    if(st){
        cout<<"YES"<<endl;
    }
    else cout<<"NO"<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin>>n>>m>>k;
    while(k--){
        solve();
    }
    return 0;
}

<3>(洛谷P2058)

周二天梯赛的一道题,当时拿了四十分,暴力解法。本来看懂代码之后想自己再写一遍的,但是一直过不了,改着改着就改成跟学长的代码一模一样了…加了点自己的注释理解,下周有时间再做一次。
题解:
题意较为繁琐,n行数据分别输入到达海港的时间t和船上的乘客数量k,k个整数表示船上乘客的国籍,试求出86400秒内所有乘船到达的乘客来自多少个不同的国家。
mp用于记录国籍与人数,所以只需输出mp.size()就可以知道国家数,q升序排列时间与国家,时间用于确认二十四小时以内,国家数等于0的时候清除此mp,每次运作都要弹出q。

代码:

#include <iostream>
#include <map>
#include <queue>
using namespace std;

#define PII pair<int,int>
map<int,int>mp;
priority_queue<PII,vector<PII>,greater<PII>>q;            //以q.first后second的升序队列

int main() {
    int n;
    std::cin>>n;
    while(n--){
        long long t,k;
        cin>>t>>k;
        while(!q.empty()&&t-86400>=q.top().first){      //从最小的开始,不符合条件的弹出
            mp[q.top().second]--;
            if(mp[q.top().second]==0){
                mp.erase(q.top().second);           //清除这个mp为后面计算size作准备
            }
            q.pop();
        }
        for(int i=1;i<=k;i++){
            int x;
            cin>>x;
            mp[x]++;                                   //mp用于计算国籍与人数
            q.push({t,x});                   //输入
        }
        cout<<mp.size()<<endl;
    }
    return 0;
}

2.高精度运算法

<1>(CF Gym104678F)

其实已经是寒假的一道题了,做天梯练习题的时候做到了一题高精度算法,没做出来,这可能就是没补题的后果,要是补题了可能就做出来了,还是先上网学习了之后再写的,过了这题先。
题解:
题意非常简单,给出俩个小于十的十的十五次方的数字,求和。
由于数据范围已经超过long long了,也没有比的更大的int类型,所以得采用string字符串的方式,逐位相加并输出,注意要是最大一位超过十要进一即可。

代码:

#include<iostream>
#include<vector>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    string a, b;
    cin >> a >> b;
    vector<int> A, B;
    for (int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i--)B.push_back(b[i] - '0');
    int t = 0;
    vector<int> c;
    for (int i = 0; i < a.size() || i < b.size(); i++) {
        if (i < a.size())t += A[i];
        if (i < b.size())t += B[i];
        c.push_back(t % 10);
        t /= 10;
    }
    if (t)c.push_back(1);
    for (int i = c.size() - 1; i >= 0; i--) {
        cout << c[i];
    }
    return 0;
}

<2>(SMU 2024 spring 天梯训练1 7—7)

整除光棍 分数20

题解:
给出一个不以5结尾的正奇数x,求s使二者相乘的数字全部由1组成,输出s以及有几个1数n。
直接暴力对t(只包含1的光棍数会超时),但是ioi赛制,15分,考虑对其余数进行相应操作,代码写得有点问题可优化。大致思路如下,可将几个if判断合并,count计算的是位数n。
代码:

#include<iostream>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int x;
    cin>>x;
    long long int t=1;
    int ans=1;
    while(t%x!=0){
        t=t*10+1;
        ans++;
    }
    cout<<t/x<<' '<<ans;
    return 0;
}
#include<iostream>
#include<vector>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int x;
    cin >> x;
    int count;
    long long int n;
    int s[1000000];
    if (x == 1) {
        cout << 1 << ' ' << 1 << endl;
    } else if (x == 3) {
        cout << 37 << ' ' << 3 << endl;
    } else if (x == 7) {
        cout << 15873 << ' ' << 6 << endl;
    } else if (x == 9) {
        cout << 12345679 << ' ' << 9 << endl;
    } else if (x == 11) {
        cout << 1 << ' ' << 2 << endl;
    }
    if (11 < x && x <= 110) {
        n = 111;
        int j = 0;
        s[j] = n / x;
        n = n % x;
        count = 3;
        while (n != 0) {
            j++;
            n = n * 10 + 1;
            s[j] = n / x;
            n = n % x;
            count++;
        }
        for (int i = 0; i <= count - 3; i++) {
            cout << s[i];
        }
        cout << ' ' << count << endl;
    }
    if (x == 111) {
        cout << 1 << ' ' << 3 << endl;
    }
    if (111 < x && x <= 999) {
        n = 1111;
        int j = 0;
        s[j] = n / x;
        n = n % x;
        count = 4;
        while (n != 0) {
            j++;
            n = n * 10 + 1;
            s[j] = n / x;
            n = n % x;
            count++;
        }
        for (int i = 0; i <= count - 4; i++) {
            cout << s[i];
        }
        cout << ' ' << count << endl;
    }
    return 0;
}

3.其它

<1>(洛谷P5657)

一道我们天梯训练赛的25分题在luogu里竟然是签到题…我当时一点思路也没有结果就这么几行代码。

#include<iostream>
using namespace std;
int n;
unsigned long long k;
int main(){
   	std::cin>>n>>k;
    k^=k>>1;                  //k跟k右移一位的数字异或的结果赋值给k
    while(n--)
    std::cout<<(k>>n&1);      //循环n次输出此数即可
    //每次输出k右移n位后的数字与1按位与后的第一位数字
}

三、总结

Clang-format的使用是ctrl+alt+l,注意格式化代码,以后争取手写。
感知了一下我的水准,20分以下还是能拿下的,20分可能会有不会做的(但是能拿不少分),25分可能会有会做的,30绝对不会做。感知我的水准还是比较精准的,但是平时的练习题会比比赛题简单很多,最好能争取平时练习题二十五分及以下全都做出来。我在说什么我一点也写不出来25分题我在梦游吧…算了一下20分及以下总共一百分,俩道二十五分题就可以拿一百五,加油。
就这样吧,做了点天梯练习题的低分题,一直卡真服了。

  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值