牛客算法竞赛入门课第二节习题 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.
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; }