牛客算法竞赛入门课第二节习题 Part1
必知:sort用法https://www.cnblogs.com/program-ai-cv-ml-se-fighting/p/11924550.html
##update:吐泡泡
思路:
用栈模拟一下就好,但是要注意当两个小泡泡合成大泡泡时是否会有两个大泡泡消除。
另外本题是多组输入。
代码:
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=43860424&returnHomeType=1&uid=115850812

1.Laptop

思路:(sort排序+枚举)

用结构体存储一下属性,sort排序后直接两层for枚举。

对于每一台笔记本,我们只需要找到一个m,s都比他大的笔记本即可,所以在内层循环可以从大到小循环,遇到完虐他的直接break内层循环即可。

如果条件再多的话,也可以考虑用线段树/树状数组/RMQ过。

代码:

#include<bits/stdc++.h> 
using namespace std;
const int maxn=1e6+7;
struct node{
    int m,s;//结构体存储信息
}a[maxn];
int n;

bool cmp(node a,node b){//二维偏序排序
    if(a.m==b.m) return a.s<b.s;
    return a.m<b.m;
}

int main(){
///输入信息
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i].m>>a[i].s;
    }
//排序
    sort(a+1,a+1+n,cmp);
    int cnt=0;
    for(int i=1;i<=n;i++){
        for(int j=n;j>i;j--)
            if(a[i].s<a[j].s&& a[i].m <a[j].m){//编号为u的笔记本电脑被完虐,计数后跳出循环即可
                cnt++;
                break;
            }
    }
    cout<<cnt<<endl;
    return 0;
}

2 .大吉大利,今晚吃鸡

思路:(递归)
仿照汉诺塔的思路即可,但是本题是 限定圆盘只能够移动到相邻的柱子
所以

void dfs(char a,char b,char c,int n){
    if(!n) return ;///n==0 所有盘子都已经被转移 递归结束
    dfs(a,b,c,n-1);///把n-1个盘子从b移动到c
    cnt++;//把第n个从a移动到b
    dfs(c,b,a,n-1);///把n-1个盘子从b移动到a
    cnt++;//把第n个盘子从b移动到c
    dfs(a,b,c,n-1);//把n-1个盘子从b移动到c
}

代码:

#include<bits/stdc++.h> 
using namespace std;
int cnt=0;
void dfs(char a,char b,char c,int n){
    if(!n) return ;
    dfs(a,b,c,n-1);cnt++;
    dfs(c,b,a,n-1);cnt++;
    dfs(a,b,c,n-1);
}
int main(){
    int n;
    while(cin>>n){
       cnt=0;
       dfs('a','b','c',n);
        cout<<cnt<<endl;
    }
    return 0;
}

3.简单的数据结构

思路:(stl之vector的使用)

对应题意说一下几个操作,记vector为v

0 .

v.begin() 返回指向容器最开始位置数据的指针

v.end() 返回指向容器结束位置数据的指针

1.

在v的开头插入元素 v.insert()

 v.insert(v.begin(),8);//在最前面插入新元素,此时v为8 2 7 9 5
 v.insert(v.begin()+3,1);//在迭代器中下标为3的元素前插入新元素,此时v为8 2 7 1 9 5
 v.insert(v.end(),3);//在向量末尾追加新元素,此时v为8 2 7 1 9 5 3
 v.insert(v.end(),3,0);//在尾部插入3个0,此时v为8 2 7 1 9 5 3 0 0 0

2.

stl中erase用法

v.erase(it);///it为迭代器类型
//表示删除容器里it所指位置的元素

3.

正常的vector插入就是在尾部插入,v.push_back(x)即可。

4.

pop_back()可以删除最后一个元素.

5.

reverse函数会将一段区间内的数逆转

6.

v.size()表示容器大小;

for(auto tt:v) 表示按照顺序依次从v中取出元素tt

7.

sort即可。

代码:

#include<bits/stdc++.h> 
using namespace std;
int main(){
    vectorv;
    int n,m;
    cin>>n>>m;
    while(m--){
        int op;cin>>op;
        if(op==1){
            int w;cin>>w;
            v.insert(v.begin(),w);
        }
        else if(op==2){
            v.erase(v.begin());
        }
        else if(op==3){
            int w;cin>>w;
            v.push_back(w);
        }
        else if(op==4){
            v.pop_back();
        }
        else if(op==5){
            reverse(v.begin(),v.end());
        }
        else if(op==6){
            cout<<v.size()<<endl;
            for(auto tt:v){
                cout<<tt<<" ";
            }
            puts("");
        }
        else sort(v.begin(),v.end());
    }
    return 0;
}

4.栈和排序

思路:(栈+优先队列)

字典序最大即是要尽可能的要按照n,n-1,n-2的顺序。

所以当能够这样时,我们要尽可能这样。

可以将数放到大根堆里,然后逐个与数组里的数比较,如果当前数组里的数是最大值的话直接输出即可,否则就放到栈内,最后进行输出。

代码:

#include<bits/stdc++.h> 
using namespace std;
const int maxn=1e6+7;
int a[maxn];
int main(){
    int n;scanf("%d",&n);
    priority_queue q;
    stackstk;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        q.push(a[i]);
    }
    for(int i=1;i<=n;i++)
        if(a[i]==q.top()) printf("%d ",q.top()),q.top();
        else stk.push(a[i]);
    while(stk.size()){///栈非空
        printf("%d ",stk.top());
        stk.pop();
    }
    return 0;
}

5.竞赛技巧

思路:(sort排序)

可以在输入的时候将时间化成秒,排序的时候直接按总和排;

也可以排序的时候逐个比较。

代码:

#include<bits/stdc++.h> 
using namespace std;
const int maxn=5100;
struct node{
    int h,m,s;
    int sum;
}a[maxn];

bool cmp1(node a,node b){
    return a.sum<b.sum;
}

bool cmp2(node a,node b){
    if(a.h==b.h&&a.m==b.m) return a.s<b.s;
    if(a.h==b.h) return a.m<b.m;
    return a.h<b.h;
}

int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>a[i].h>>a[i].m>>a[i].s;
        a[i].sum=a[i].h*60*60+a[i].m*60+a[i].s;
    }
  ///  sort(a+1,a+1+n,cmp1);
    sort(a+1,a+1+n,cmp2);
    for(int i=1;i<=n;i++)
        cout<<a[i].h<<" "<<a[i].m<<" "<<a[i].s<<endl;
    return 0;
}

6.老子的全排列呢

思路:(dfs 或全排列函数)

代码:

#include<bits/stdc++.h> 
using namespace std;
const int maxn=10;

int main(){
    int a[8]={1,2,3,4,5,6,7,8};//初始化数组
    do{
        for(int i=0;i<8;i++){//输出
            cout<<a[i];
            if(i==7) puts("");
            else cout<<" ";
        }
    }while(next_permutation(a,a+8));///全排列函数,将指定区间的数组进行全排列,也可用dfs实现
    return 0;
}

7.逆序数

思路:(归并排序或树状数组)

归并排序详解

代码:(直接搬的很久以前写的代码0.0)

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll; 
const int N = 100010;
int a[N],t[N];
ll f(int a[],int l,int r){
    if(l>=r) return 0;
    int mid = (l + r)/2 ;
    ll res = f(a,l,mid) + f(a,mid + 1 ,r);
    int k = 0,i = l,j = mid + 1;
    while(i <= mid && j <= r) 
        if(a[i] <= a[j]) t[k++]=a[i++];
        else{
            res += mid - i + 1;
            t[k++] = a[j++]; 
        }
    while(i <= mid) t[k++] = a[i++];
    while(j <= r) t[k++]= a[j++];
    for(i = l,j = 0;i <= r;i++,j++) a[i]=t[j];
    return res;
}
int main(){
    int n;
    cin>>n;
    for(int i = 0;i < n;i ++ ) scanf("%d",&a[i]);
    cout<<f(a,0,n-1)<<endl;
}

8 .The Biggest Water Problem

思路:(递归+模拟)

代码:

#include<bits/stdc++.h> 
using namespace std;
int cul(int n){
    if(n<10) return n;//当n<10时结束递归
    int sum=0;
    while(n) sum+=n%10,n/=10;//得到各位数之和
    return cul(sum);//返回结果
}
int main(){
    int n;cin>>n;
    cout<<cul(n)<<endl;
    return 0;
}

9.小C的记事本

思路:(栈+字符串模拟)

代码:

#include<bits/stdc++.h> 
using namespace std;
stackres;
int main(){
    ios::sync_with_stdio(false);//读入写优化,加上这句只能用cin.cout;用scanf会WA!
    int q;
    while(cin>>q){
        string s="";
        while(q--){
            int op;cin>>op;
            if(op==1){
                string tmp;cin>>tmp;
                res.push(s);
                s=s+tmp;//插入字符串
            }
            else if(op==2){
               int k;cin>>k;
                res.push(s);
                s=s.substr(0,s.size()-k);//删除后k个字符
            }
            else if(op==3){
                int k;cin>>k;
                cout<<s[k-1]<<endl;//输出第k个字符,但是因为s的下标是从0开始,所以输出s[k-1]
            }
            else{
                s=res.top();//res存储的是上一个状态
                if(!res.empty()) res.pop();
            }
        }
        while(!res.empty()) res.pop();
    }
    return 0;
}

10 .分数线划定

思路:(结构体排序)

注意如何求有多少人入选面试的方法,有可能那个分数线是好几个人同时拥有的,这时候人数就比m大了。

代码:

#include<bits/stdc++.h> 
using namespace std;
const int maxn=1e6+7;

struct node{
    int num,score;
}a[maxn];
int n,m;

bool cmp(node a,node b){//按照题目要求排序
    if(a.score==b.score) return a.num<b.num;
    return a.score>b.score;
}

int main(){
//输入
    cin>>n>>m;
    for(int i=1;i>a[i].num>>a[i].score;
//按照题目排序
    sort(a+1,a+1+n,cmp);
    int t=m*1.5;//假设人数
//特判相等人数
    while(t<=n&&a[t].score==a[t+1].score) t++;
    cout<<a[t].score<<" "<<t<<endl;
    for(int i=1;i<=t;i++)///输出结果

        cout<<a[i].num<<" "<<a[i].score<<endl;
    return 0;
}