HRBU 2021年暑期训练Day1

目录

A、Stack

B、Queue

C、Shaolin

D、Equal Sums

 E - Potions (Hard Version)

 F - Buy and Resell

 G - 度度熊学队列


A、Stack

题目链接:HRBU 2021年暑期训练Day1 - Virtual Judge

题目理解:题目给我们一个表达式,要求我们算出这个表达式的最终结果并且输出,注意这个表达式的形式是一个逆波兰式

什么叫逆波兰式呢

举个例子,1+2=3,这种式子叫做正则表达式,而这个式子的逆波兰式表达就是1 2 + 3 =,也就是我们的操作数写在前面,对应的算术操作写在操作数之后

做法:因为操作数在前,而对应的算术操作在后面,我们考虑,用一个方法把数字存起来,然后在遇到算术操作符的时候就把两个数字进行对应的操作,最后得出一个结果。这里引入一个C++STL库里的stack。这个函数的有关知识推荐点击下面这个链接进行了解

函数介绍链接:C++ STL 详解_Five—菜鸟级的博客-CSDN博客_c++stl详解

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int maxx=1e7+10;
const int maxn=1e4+10;
ll m,t,n;
int main()
{
    char s[1010];
    stack<int> S;
    while(scanf("%s",s)!=EOF)
    {
        if(s[0]=='+')
        {
            m=S.top();
            S.pop();
            n=S.top();
            S.pop();
            S.push(m+n);
        }
        else if(s[0]=='-')
        {
            m=S.top();
            S.pop();
            n=S.top();
            S.pop();
            S.push(n-m);
        }
        else if(s[0]=='*')
        {
            m=S.top();
            S.pop();
            n=S.top();
            S.pop();
            S.push(m*n);
        }
        else
        {
            S.push(atoi(s));
        }
    }
    printf("%d\n",S.top());
    return 0;
}
/*

*/

B、Queue

题目链接:HRBU 2021年暑期训练Day1 - Virtual Judge

题目理解:题目给了我们一个包含n个进程的队列,每一个进程都有对应的名称namei以及对应的完成时间timei,要我们去模拟队列里进程的调度过程,当所有的进程完成时,按进程调度的完成顺序来输出第i个完成调度的进程名以及王完成时间

做法:首先我们得了解进程调度的一个基本流程,进程调度优先顺序按照进入队列的顺序来,先进先出,当这个进程被调用时,如果这个进程已经完成调度了,我们就直接把这个进程给输出,否则的话,就继续放到队尾,等待下一次的调度,结果输出其实就是按照完成时间的先后顺序来输出进程名以及完成时间。这里又有一个新的STL的知识队列Queue,还是链接,自行了解

函数介绍链接:C++ STL 详解_Five—菜鸟级的博客-CSDN博客_c++stl详解

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int maxx=1e7+10;
const int maxn=1e5+10;
int m,t,n,q;
struct Node{
    string s;
    int t;
}P;
queue<Node> Q;

int main(){
    while(cin>>n>>q){
        int T=0;
        for(int i=1;i<=n;i++){
            cin>>P.s>>P.t;
            Q.push(P);
        }
        while(!Q.empty()){
            Node now=Q.front();
            Q.pop();
            int x=min(q,now.t);
            now.t-=x;
            T+=x;
            if(now.t>0)
                Q.push(now);
            else
                cout<<now.s<<" "<<T<<endl;
        }
    }
    return 0;
}
/*

*/

C、Shaolin

题目链接:HRBU 2021年暑期训练Day1 - Virtual Judge

题目理解:加入少林寺的规则是需要寻找一个和自己战斗力差不多的和尚(已存在的数据),要是有两个人符合条件则选择战斗力低于自己的,目前告诉我们初始数据是id为1的战斗力为10亿的第一个数据,以及目前少林中有的所有人的数据(输入顺序按照进入少林的时间顺序先后),要求你输出所有的战斗记录,输出新和尚id和他对战的老和尚id

做法:在输入的时候进行处理,新数据要进去数组的话,就需要和老数据进行对比,我们先把新数据在已有的数据中进行遍历查找,找到某个位置x满足

x-1的战斗力<=x的战斗力<=x+1的战斗力

当我们存储完成时只需要比较前一位的战斗力差和后一位的战斗力差哪个更小即可

所以我们就要考虑该怎么去存储这个数据,在保证数据有序的同时时间复杂度还不会超出范围,引入一个STL的map,map内部默认数据输入的话就会进行排序(从小到大),所以我们就考虑用map<int,int>去表示一个和尚,前一位存储战斗力,后一位存储id。

注:还需要了解一下map的遍历(需要迭代器)

函数介绍链接:C++ STL 详解_Five—菜鸟级的博客-CSDN博客_c++stl详解

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int t,n;

int main()
{
    while(cin>>t&&t!=0)
    {
        int id,power;
        map<int,int> mp;
        mp[1000000000]=1;
        for(int i=1; i<=t; i++)
        {
            cin>>id>>power;
            map<int,int>::iterator itl,itr,it=mp.lower_bound(power);
            itl=itr=it;
            if(itl!=mp.begin())
                itl--;
            if(power-itl->first>it->first-power)
                itl=itr;
            cout<<id<<" "<<itl->second<<endl;
            mp[power]=id;
        }
    }
    return 0;
}

D、Equal Sums

题目链接:HRBU 2021年暑期训练Day1 - Virtual Judge

题目理解:题目给了我们k个整数序列,标明的每一个序列的长度以及内部元素,要求我们找出两个序列,做到删除序列中两个元素后两个序列的序列和相同,能满足条件则输出

YES

选择的序列1以及删除的元素位置1

选择的序列2以及删除的元素位置2

否则输出NO

做法:首先我们把序列的和给求出来,然后用序列里每一个元素通过序列和减去这个元素的值,去和其他的序列进行对比,要是有相同的数据就直接输出。这里引入一个新的数据结构类型pair

pair可以和map,vector等一起连用,可以达到不同的存储效果

比如vector<pair<int,int> >,就可以在一个数组里进行存储和计数两个操作了

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int t,n;

int main()
{
    int k;
    cin>>k;
    map<int,pair<int,int> > mp;
    for(int i=1;i<=k;i++)
    {
        int arr[maxn],n,sum=0;
        memset(arr,0,sizeof(arr));
        cin>>n;
        for(int j=1;j<=n;j++)
        {
            cin>>arr[j];
            sum+=arr[j];
        }
        for(int j=1;j<=n;j++)
        {
            if(mp.count(sum-arr[j]))
            {
                cout<<"YES"<<endl;
                cout<<i<<" "<<j<<endl;
                cout<<mp[sum-arr[j]].first<<" "<<mp[sum-arr[j]].second<<endl;
                return 0;
            }
        }
        for(int j=1;j<=n;j++)
        {
            mp[sum-arr[j]]=make_pair(i,j);
        }
    }
    cout<<"NO"<<endl;
    return 0;
}

 E - Potions (Hard Version)

题目链接:HRBU 2021年暑期训练Day1 - Virtual Judge

题目理解:给你一组数据,这个数组里面的元素的值是整数(有正有负),而你的初始值为0,你要去将这一组数据进行累加(对于一个元素你可以考虑是累加或者是不累加),要求这一期间你的结果不能小于0,问你最多能累加多少个数据

做法:对于每一个数据都进行判断,要是当前这个数据加上之前的和已经小于0了,那就考虑把之前累加的数据里面最小的那个数字给踢出,来保证里面数据的最大化,否则就把这个数据添加进来。由于这个过程中我们必须保证数据的添加,数据的大小比较以及数据的删除的操作消耗的时间复杂度必须要小,所以我们引入一个新的STLpriority_queue(优先队列),这个可以完成刚刚我的描述里的操作,而且也能保证时间复杂度,可以参考一下这个博客,个人学习后感觉很棒

博客链接:c++优先队列(priority_queue)用法详解 - 华山青竹 - 博客园

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int maxx=1e7+10;
const int maxn=2e5+10;
ll n;
priority_queue<ll,vector<ll>,greater<ll>> Q;

int main(){
    while(cin>>n){
        ll sum=0,num=0,x;
        for(int i=1;i<=n;i++){
            cin>>x;
            if(sum+x>=0){
                sum+=x;
                num++;
                Q.push(x);
            }
            else if(Q.size()&&Q.top()<x){
                sum+=x-Q.top();
                Q.pop();
                Q.push(x);
            }
        }
        cout<<num<<endl;
    }
    return 0;
}
/*

*/

 F - Buy and Resell

题目链接:HRBU 2021年暑期训练Day1 - Virtual Judge

题目理解:给你n个数据,对于每个数据你可以有三种选择1、买入这个数据,你将会损失ai。2、卖出这个数据,你将获得ai。3、不进行任何操作。问你能否通过最少的操作次数来获得一个最大值,可以的话输出这个最大值和操作次数。

做法:首先你要明确,一开始你拥有0,那么你如果想要最后的结果最大的话,那么是不是应该在数据选择的时候,进行判断,当前的这个数据是否比我前一位买入的那个数据要大,要是大于的话,我买入这个数据再卖出,我的最终答案一定是正增长,否则我就不考虑买入。回到数据操作问题,那么我需要的就是一个可以随时排序的队列,来保证我买入的数据一定是大的数据在前,小的数据在后,和上一题其实类似,也是用优先队列来完成,不过这一题的优先队列的类型以及内部的排序规则,得自己定义

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;

struct Node
{
    ll num,pos;
    friend bool operator < (Node a,Node b)
    {
        if(a.num==b.num)
            return a.pos<b.pos;
        return a.num>b.num;
    }
};

int main()
{
    int T,n,a[maxn];
    scanf("%d",&T);
    while(T--)
    {
        ll ans=0,cnt=0;
        priority_queue<Node> Q;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int x;
            Node now;
            scanf("%d",&x);
            Q.push((Node){x,0});
            now=Q.top();
            if(x>now.num)
            {
                ans+=(x-now.num);
                Q.pop();
                Q.push((Node){x,1});
            }
        }
        while(!Q.empty())
        {
            if(Q.top().pos)
                cnt++;
            Q.pop();
        }
        cout<<ans<<" "<<cnt*2<<endl;
    }
    return 0;
}

 G - 度度熊学队列

题目链接:HRBU 2021年暑期训练Day1 - Virtual Judge

题目理解:模拟双端队列的过程

做法:没有做法!就是去模拟双端队列的一个基本操作,然后在输入的判断以及输出的格式上稍加注意就行,deque的详解也推荐是下面这个博客(真的好用,里面都是STL)

博客链接:C++ STL 详解_Five—菜鸟级的博客-CSDN博客_c++stl详解

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include <fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;

int main()
{
    int N,Q;
    while(~scanf("%d%d",&N,&Q))
    {
        deque<int>de[N+1];
        while(Q--)
        {
            char o;
            int u,v,val;
            scanf(" %c",&o);
            if(o=='3')
            {
                scanf("%d%d%d",&u,&v,&val);
                if(val==0)
                {
                    while(!de[v].empty())
                    {
                        de[u].push_back(de[v].front());
                        de[v].pop_front();
                    }
                }
                else
                {
                    while(!de[v].empty())
                    {
                        de[u].push_back(de[v].back());
                        de[v].pop_back();
                    }
                }
            }
            else if(o=='2')
            {
                scanf("%d%d",&u,&v);
                if(de[u].empty())
                    printf("-1\n");
                else if(v==0)
                {
                    printf("%d\n",de[u].front());
                    de[u].pop_front();
                }
                else
                {
                    printf("%d\n",de[u].back());
                    de[u].pop_back();
                }
            }
            else if(o=='1')
            {
                scanf("%d%d%d",&u,&v,&val);
                if(v==0)
                    de[u].push_front(val);
                else
                    de[u].push_back(val);
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值