L1-6 吉老师的回归
曾经在天梯赛大杀四方的吉老师决定回归天梯赛赛场啦!
为了简化题目,我们不妨假设天梯赛的每道题目可以用一个不超过 500 的、只包括可打印符号的字符串描述出来,如:Problem A: Print "Hello world!"
。
众所周知,吉老师的竞赛水平非常高超,你可以认为他每道题目都会做(事实上也是……)。因此,吉老师会按照顺序看题并做题。但吉老师水平太高了,所以签到题他就懒得做了(浪费时间),具体来说,假如题目的字符串里有 qiandao
或者 easy
(区分大小写)的话,吉老师看完题目就会跳过这道题目不做。
现在给定这次天梯赛总共有几道题目以及吉老师已经做完了几道题目,请你告诉大家吉老师现在正在做哪个题,或者吉老师已经把所有他打算做的题目做完了。
提醒:天梯赛有分数升级的规则,如果不做签到题可能导致团队总分不足以升级,一般的选手请千万不要学习吉老师的酷炫行为!
输入格式:
输入第一行是两个正整数 N,M (1≤M≤N≤30),表示本次天梯赛有 N 道题目,吉老师现在做完了 M 道。
接下来 N 行,每行是一个符合题目描述的字符串,表示天梯赛的题目内容。吉老师会按照给出的顺序看题——第一行就是吉老师看的第一道题,第二行就是第二道,以此类推。
输出格式:
在一行中输出吉老师当前正在做的题目对应的题面(即做完了 M 道题目后,吉老师正在做哪个题)。如果吉老师已经把所有他打算做的题目做完了,输出一行 Wo AK le
。
输入样例 1:
5 1
L1-1 is a qiandao problem.
L1-2 is so...easy.
L1-3 is Easy.
L1-4 is qianDao.
Wow, such L1-5, so easy.
输出样例 1:
L1-4 is qianDao.
输入样例 2:
5 4
L1-1 is a-qiandao problem.
L1-2 is so easy.
L1-3 is Easy.
L1-4 is qianDao.
Wow, such L1-5, so!!easy.
输出样例 2:
Wo AK le
收获:字符串的find函数可以直接寻找需要的目标字符,返回-1说明字符串不含目标字符,找到了就返回第一个字符的位置。
AC代码:
#include <iostream>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
int n,m;
int main(int argc, char** argv) {
cin>>n>>m;
getchar();
int k=0;
int f=1;
string s;
while(n--)
{
getline(cin,s);
if(s.find("qiandao")==-1&&s.find("easy")==-1)
k++;
if(k>m&&f==1)
{
cout<<s<<endl;
f=0;
}
}
if(k<=m&&f==1)
cout<<"Wo AK le\n";
return 0;
}
L1-8 乘法口诀数列
本题要求你从任意给定的两个 1 位数字 a1 和 a2 开始,用乘法口诀生成一个数列 {an},规则为从 a1 开始顺次进行,每次将当前数字与后面一个数字相乘,将结果贴在数列末尾。如果结果不是 1 位数,则其每一位都应成为数列的一项。
输入格式:
输入在一行中给出 3 个整数,依次为 a1、a2 和 n,满足 0≤a1,a2≤9,0<n≤103。
输出格式:
在一行中输出数列的前 n 项。数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
2 3 10
输出样例:
2 3 6 1 8 6 8 4 8 4
样例解释:
数列前 2 项为 2 和 3。从 2 开始,因为 2×3=6,所以第 3 项是 6。因为 3×6=18,所以第 4、5 项分别是 1、8。依次类推…… 最后因为第 6 项有 6×8=48,对应第 10、11 项应该是 4、8。而因为只要求输出前 10 项,所以在输出 4 后结束。
收获:动态数组可以自动添加数组长度,不用静态地管理数组位置。
AC代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char** argv) {
int a,b,m;
cin>>a>>b>>m;
vector<int> arr;
arr.push_back(a);
arr.push_back(b);
int i=2;
while(i<=m)
{
int t=a*b;
if(t>=10)
{
arr.push_back(t/10);
arr.push_back(t%10);
}
else
arr.push_back(t);
a=arr[i-1];
b=arr[i];
i++;
}
for(int i=0;i<m;i++)
{
if(i!=0)cout<<" ";
cout<<arr[i];
}
return 0;
}
L2-1 包装机
一种自动包装机的结构如图 1 所示。首先机器中有 N 条轨道,放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时,活塞向左推动,将轨道尽头的一件物品推落筐中。当 0 号按钮被按下时,机械手将抓取筐顶部的一件物品,放到流水线上。图 2 显示了顺序按下按钮 3、2、3、0、1、2、0 后包装机的状态。
图1 自动包装机的结构
图 2 顺序按下按钮 3、2、3、0、1、2、0 后包装机的状态
一种特殊情况是,因为筐的容量是有限的,当筐已经满了,但仍然有某条轨道的按钮被按下时,系统应强制启动 0 号键,先从筐里抓出一件物品,再将对应轨道的物品推落。此外,如果轨道已经空了,再按对应的按钮不会发生任何事;同样的,如果筐是空的,按 0 号按钮也不会发生任何事。
现给定一系列按钮操作,请你依次列出流水线上的物品。
输入格式:
输入第一行给出 3 个正整数 N(≤100)、M(≤1000)和 Smax(≤100),分别为轨道的条数(于是轨道从 1 到 N 编号)、每条轨道初始放置的物品数量、以及筐的最大容量。随后 N 行,每行给出 M 个英文大写字母,表示每条轨道的初始物品摆放。
最后一行给出一系列数字,顺序对应被按下的按钮编号,直到 −1 标志输入结束,这个数字不要处理。数字间以空格分隔。题目保证至少会取出一件物品放在流水线上。
输出格式:
在一行中顺序输出流水线上的物品,不得有任何空格。
输入样例:
3 4 4
GPLT
PATA
OMSA
3 2 3 0 1 2 0 2 2 0 -1
输出样例:
MATA
收获:栈与队列的操作
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
typedef long long ll;
void s()
{
int n,m,smax;
cin>>n>>m>>smax;
char c;
queue<char> a[n+5];
stack<char> b;
for(int i=1;i<=n;i++ ) //进队
{
for(int j=0;j<m;j++)
{
cin>>c;
a[i].push(c);
}
}
int x;
while(1)
{
cin>>x;
if(x==-1) //x=-1,不符合跳出
break;
if(x==0&&!b.empty())
{
cout<<b.top();//取出栈顶
b.pop();
}
if(b.size()<smax&&!a[x].empty())
{
b.push(a[x].front());//将队首放入栈
a[x].pop();//弹出队首
}
else if(!a[x].empty()) //栈满 但队还有东西
{
cout<<b.top();//输出栈顶
b.pop();//弹出栈顶
b.push(a[x].front());//取队首放入栈中
a[x].pop();//弹出队首
}
}
}
int main(int argc, char** argv) {
s();
return 0;
}
L2-2 病毒溯源
病毒容易发生变异。某种病毒可以通过突变产生若干变异的毒株,而这些变异的病毒又可能被诱发突变产生第二代变异,如此继续不断变化。
现给定一些病毒之间的变异关系,要求你找出其中最长的一条变异链。
在此假设给出的变异都是由突变引起的,不考虑复杂的基因重组变异问题 —— 即每一种病毒都是由唯一的一种病毒突变而来,并且不存在循环变异的情况。
输入格式:
输入在第一行中给出一个正整数 N(≤104),即病毒种类的总数。于是我们将所有病毒从 0 到 N−1 进行编号。
随后 N 行,每行按以下格式描述一种病毒的变异情况:
k 变异株1 …… 变异株k
其中 k
是该病毒产生的变异毒株的种类数,后面跟着每种变异株的编号。第 i 行对应编号为 i 的病毒(0≤i<N)。题目保证病毒源头有且仅有一个。
输出格式:
首先输出从源头开始最长变异链的长度。
在第二行中输出从源头开始最长的一条变异链,编号间以 1 个空格分隔,行首尾不得有多余空格。如果最长链不唯一,则输出最小序列。
注:我们称序列 { a1,⋯,an } 比序列 { b1,⋯,bn } “小”,如果存在 1≤k≤n 满足 ai=bi 对所有 i<k 成立,且 ak<bk。
输入样例:
10
3 6 4 8
0
0
0
2 5 9
0
1 7
1 2
0
2 3 1
输出样例:
4
0 4 9 1
收获:动态数组可自动进行多维数组的使用
AC代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N = 10100;
vector<int>v[N];
vector<int>temp;
//使用Vector动态数组可进行多维数组的使用
int t[N];
int n;
void dfs(int gen,vector<int>&p)
{
if(p.size()>temp.size())//找到更深的长度,更新temp数组
{
temp.clear();
temp=p;
}
for(int i=0;i<v[gen].size();i++) //查找根节点的每个孩子节点
{
p.push_back(v[gen][i]);
dfs(v[gen][i],p);//深搜根节点
p.pop_back();//回溯
}
}
int main(int argc, char** argv) {
cin>>n;
for(int i=0;i<n;i++)
{
int k;
cin>>k;
while(k--)
{
int x;
cin>>x;
v[i].push_back(x);
t[x]=1;//将所有的孩子节点都设置为1 ,不是1的就是根节点
}
if(v[i].size())
{
sort(v[i].begin(),v[i].end()); //每一行的孩子都是从小到大排列
}
}
for(int i=0;i<n;i++)
{
if(t[i]!=1) //根节点
{
vector<int>p;
p.push_back(i);
dfs(i,p);//从根节点开始搜,每次都更新数组p
break;
}
}
cout<<temp.size()<<endl;
for(int i=0;i<temp.size();i++)
{
cout<<temp[i];
if(i!=temp.size()-1) cout<<" ";
}
return 0;
}
L2-3 清点代码库
上图转自新浪微博:“阿里代码库有几亿行代码,但其中有很多功能重复的代码,比如单单快排就被重写了几百遍。请设计一个程序,能够将代码库中所有功能重复的代码找出。各位大佬有啥想法,我当时就懵了,然后就挂了。。。”
这里我们把问题简化一下:首先假设两个功能模块如果接受同样的输入,总是给出同样的输出,则它们就是功能重复的;其次我们把每个模块的输出都简化为一个整数(在 int 范围内)。于是我们可以设计一系列输入,检查所有功能模块的对应输出,从而查出功能重复的代码。你的任务就是设计并实现这个简化问题的解决方案。
输入格式:
输入在第一行中给出 2 个正整数,依次为 N(≤104)和 M(≤102),对应功能模块的个数和系列测试输入的个数。
随后 N 行,每行给出一个功能模块的 M 个对应输出,数字间以空格分隔。
输出格式:
首先在第一行输出不同功能的个数 K。随后 K 行,每行给出具有这个功能的模块的个数,以及这个功能的对应输出。数字间以 1 个空格分隔,行首尾不得有多余空格。输出首先按模块个数非递增顺序,如果有并列,则按输出序列的递增序给出。
注:所谓数列 { A1, ..., AM } 比 { B1, ..., BM } 大,是指存在 1≤i<M,使得 A1=B1,...,Ai=Bi 成立,且 Ai+1>Bi+1。
收获:map结构可自动对输入的内容进行递增排序且允许重复的数
输入样例:
7 3
35 28 74
-1 -1 22
28 74 35
-1 -1 22
11 66 0
35 28 74
35 28 74
输出样例:
4
3 35 28 74
2 -1 -1 22
1 11 66 0
1 28 74 35
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
int n, m;
map<vector<int>, int> mp;
struct cmp//自定义set排序
{
bool operator() (const pair<int,vector<int> >&a, const pair<int,vector<int> >&b) const
{
if(a.first!=b.first)
return a.first>b.first;
else return a.second<b.second;
}
};
int main() {
cin >> n >> m;
vector<int> v;
for (int i = 0; i < n; i++) {
v.clear();
int f;
for (int j = 0; j < m; j++) {
cin >> f;
v.push_back(f);
}
if (!mp.count(v)) {
mp[v] = 1;
} else
mp[v]++;
}
set<pair<int, vector<int> >,cmp > ans;
for (auto it : mp) {
ans.insert({it.y, it.x});
}
cout << mp.size() << endl;
for (auto it : ans) {
cout << it.x;
for (int i = 0; i < m; i++) {
cout << " " << it.y[i];
}
cout << endl;
}
return 0;
}