HRBU 2021暑期训练解题报告Day2

目录

A - The Balance of the World

B - Stones

C - Running Median

D - Let the Balloon Rise

E - Shopping

F - pairs

G - 产生冠军

H - Kiki & Little Kiki 1


A - The Balance of the World

题意:

给出一个字符串,判断字符串中出现的括号是否全部匹配成功。

思路:

栈的入门题,简单的模拟就好了。

  • 考察点:栈(Stack),数据结构,模拟

  • 坑点:整行输入,输入结束条件

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;

int main()
{
    char c;
    stack<char> s;
    string ss;
    while(1)
    {
        getline(cin,ss);
        if(ss==".") break;
        while(!s.empty()) s.pop();
        for(int i=0; i<ss.size(); i++)
        {
            c=ss[i];
            if(c=='('||c=='[')
                s.push(c);
            else if(c==')')
            {
                if(s.empty()||s.top()!='(')
                    s.push(c);
                if(s.top()=='(')
                    s.pop();
            }
            else if(c==']')
            {
                if(s.empty()||s.top()!='[')
                    s.push(c);
                if(s.top()=='[')
                    s.pop();
            }
        }
        if(s.empty())
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }

}

B - Stones

题意:

最近小S的自行车坏了,他只能步行去学校了。
小S在去往学校的路上发现了很多小石头,正好他比较无聊,于是他便开始扔石头。

对小S的上学之路进行二维化形成坐标系(二向箔警告),小S初始位置为0。
在坐标轴的一些位置上散落着石头,每个石头能够被扔出去的距离为di。

当小S遇到一个石头时,他会先去数这是他碰到的第几个石头:

  1. 如果是第偶数个石头,小S会觉得它很无聊,会忽略它继续走;
  2. 如果是第奇数个石头,小S会把它向前扔di米。

如果有多个石头落在了同一个坐标下,小S会依据它们的di由小到大的去处理这些石头。

小S想知道他最远会在哪里停下来(当没有石头可以扔的时候小S会停下思考人生)。

思路:

定义结构体node存储每块石头的信息:

struct node
{
    int pos,x;
    bool operator<(const node a)const{   //重载运算符,定义优先级
        if(a.pos!=pos) return a.pos<pos;
        else return a.x<x;
    }
}zh;

将每块石头都存到优先队列中,优先级为距离由小到大,次优先级为被扔距离由小到大。

接下来模拟就好了。

  • 考察点:优先队列(Priority queue),数据结构,模拟,运算符重载

代码:

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
struct node
{
    int pos,x;
    bool operator<(const node a)const{   //重载运算符,定义优先级
        if(a.pos!=pos) return a.pos<pos;
        else return a.x<x;
    }
}zh;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        priority_queue<node> p;
        for(int i=0;i<n;i++){
            cin>>zh.pos>>zh.x;
            p.push(zh);
        }
        int pos=0;
        int num=0;
        while(!p.empty()){
            node tmp=p.top();
            p.pop();
            num++;
            //cout<<tmp.pos<<" "<<tmp.x<<endl;

            if(num&1){
                tmp.pos+=tmp.x;
                p.push(tmp);
            }
            else{
                pos=tmp.pos;
            }
        }
        cout<<pos<<endl;
    }

}

C - Running Median

题意:

给定一个长为n的序列,请你求出每当我们考虑前k(k=1;k<=n;k+=2)个数字时中位数是多少?

思路:

本套题最好玩的题(精华所在)。

对于奇数长度的序列,小于中位数的数的数量num1与大于中位数的数的数量num2满足:

num1==num2==n/2

我们可以利用这个性质,设计两个优先队列形成对顶堆:

priority_queue<int> p1;     //大根堆,存储小于等于中位数的数,p1.top()为中位数

priority_queue<int,vector<int>,greater<int> > p2;  //小根堆,存储大于中位数的数

接下来模拟题目过程,维护num1( p1.top()-1 )与num2( p2.top() )的关系。

  • 考察点: 优先队列(Priority queue),数据结构,模拟,对顶堆

  • 难点:设计对顶堆,找出p1、p2之间的关系

  • 坑点:阴间的输出格式

代码:

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int x,n,a;
        scanf("%d%d",&x,&n);
        priority_queue<int> p1; 
        priority_queue<int,vector<int>,greater<int> > p2; 

        vector<int> ans;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a);
            if(p1.empty())
                p1.push(a);
            else
            {
                if(a>p1.top())
                    p2.push(a);
                else
                    p1.push(a);
            }
            while(p1.size()<p2.size())
            {
                p1.push(p2.top());
                p2.pop();
            }
            while(p2.size()<p1.size()-1)
            {
                p2.push(p1.top());
                p1.pop();
            }
            if(i&1)
                ans.push_back(p1.top());
        }
        printf("%d %d\n",x,ans.size());
        for(int i=1; i<=ans.size(); i++)
        {
            if(i%10!=1)
                printf(" ");
            printf("%d",ans[i-1]);
            if(i%10==0)
                printf("\n");
        }
        printf("\n");
    }

}

D - Let the Balloon Rise

题意:

给出n个字符串,输出出现次数最多的字符串。

思路:

map的模板题,套就完了。

  • 考察点:映射对(Map),数据结构

代码:

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;

int main()
{
    int n;
    while(cin>>n&&n)
    {
        string ss;
        map<string,int> mp;
        for(int i=0;i<n;i++){
            cin>>ss;
            mp[ss]++;
        }
        map<string,int>::iterator it;
        int maxx=-1;
        string answer;
        for(it=mp.begin();it!=mp.end();it++){
            if(it->second > maxx){
                answer=it->first;
                maxx=it->second;
            }
        }
        cout<<answer<<endl;
    }
}

E - Shopping

题意:

现在一共有n家商店正在竞选风都第一店的名号,由你所经营的一家叫做“memory”的商店也在竞选名单之中。
每一天都会有人为这n家商店进行投票。

你想知道在每天的投票结束后你的商店可以排到第几。
(主场优势:如果另一家店的票数和“memory”的票数一样,我们则认为“memory”更加占据优势。 什么?你问我为什么? 主办方规定的,他们还负责今年的东京奥运会)

思路:

map的模板题2,每次找票数多于memory的店家数量。

  • 考察点:映射对(Map),数据结构

代码:

#include<bits/stdc++.h>
#define inf 0x3f3f3f
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
string shop="memory";
int main()
{
    int n,day,x;
    string s;
    while(cin>>n)
    {
        map<string,int>q;
        for(int i=0; i<n; i++)
        {
            getchar();
            cin>>s;
            q[s]=0;
        }
        cin>>day;
        for(int i=0; i<day; i++)
        {
            for(int j=0; j<n; j++)
            {
                getchar();
                cin>>x>>s;
                q[s]+=x;
//            cout<<s<<":"<<q[s]<<endl;
            }
            map<string,int>::iterator it;
            int ans=1;
            for(it=q.begin(); it!=q.end(); it++)
                if(q[shop]<it->second)
                    ans++;
            cout<<ans<<endl;
        }
    }
}

F - pairs

题意:

给定长度为n的序列x,请问你能找到多少对(i,j)(i < j)满足 | x[i] - x[j] | <= k。

思路:

使用lower_bound二分查找x[i]+k的位置pos,如果x[pos]-x[i]==k,则有pos-i对;否则有pos-i-1对。

  • 考察点:二分查找,数据结构,STL

代码:

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;

ll a[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll n,k;
        cin>>n>>k;
        for(int i=0;i<n;i++){
            cin>>a[i];
        }
        sort(a,a+n);
        ll cnt=0;
        for(int i=0;i<n;i++){
            int posa=lower_bound(a,a+n,a[i]+k)-a;
            if(posa==n) posa--;
            cnt+=posa-i-1;
            if(a[posa]-a[i]<=k) cnt++;
        }
        cout<<cnt<<endl;
    }
}

G - 产生冠军

题意:

思路:

产生冠军的条件:
只有一个人没有输过。

没有输过:名字没有出现在右边。

使用set容器帮助我们处理过程。

  • 考察点:集合(Set),数据结构,STL

代码:

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;

int main()
{
    int n;
    while(cin>>n&&n)
    {
        set<string> s;
        set<string> ss;
        string x,y;
        for(int i=0; i<n; i++)
        {
            cin>>x>>y;
            s.insert(y);
            ss.insert(x);
        }
        int cnt=0;
        set<string>::iterator it;
        for(it=ss.begin(); it!=ss.end(); it++)
        {
            if(s.find(*it)!=s.end())
                continue;
            else
                cnt++;
        }
        if(cnt==1)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
}

H - Kiki & Little Kiki 1

题意:

编写一个程序,模拟kiki所说的 “小kiki容器” 。

“小kiki容器”具有一下操作:

  • Push M:将M加入容器;
  • Pop M:从容器找寻找第一个小于等于M的数输出并从容器中删除,若不存在该数则输出“No Element!”

思路:

显而易见的模拟题。

multiset(可重复集合)是博主认为比较适合的容器。
模拟就完事了。

  • 考察点:可重复集合(multiset),数据结构,STL,二分查找

  • 坑点:multiset::erase()函数的参数究竟有哪些,什么含义

代码:

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;
multiset<int> mts;
multiset<int>::iterator it;
char ss[10];
int main()
{
    int n;
    while(~scanf("%d",&n)){
        mts.clear();
        int x;
        while(n--){
            scanf("%s%d",ss,&x);
            if(ss[1]=='u')
                mts.insert(x);
            else{
                it=mts.lower_bound(x);
                if(*it==x){
                    printf("%d\n",x);
                    mts.erase(it);
                }
                else if(*it!=x){
                    if(it==mts.begin())
                        printf("No Element!\n");
                    else{
                        it--;
                        printf("%d\n",*it);
                        mts.erase(it);
                    }
                }
            }
        }
        printf("\n");
    }
}

おすすめ

転載: blog.csdn.net/qq_45750296/article/details/119425052