2022年暑假ACM专项训练之STL和基本数据结构

A - 圆桌问题

圆桌上围坐着2n个人。其中n个人是好人,另外n个人是坏人。如果从第一个人开始数数,数到第m个人,则立即处死该人;然后从被处死的人之后开始数数,再将数到的第m个人处死……依此方法不断处死围坐在圆桌上的人。试问预先应如何安排这些好人与坏人的座位,能使得在处死n个人之后,圆桌上围坐的剩余的n个人全是好人。 

Input

多组数据,每组数据输入:好人和坏人的人数n(<=32767)、步长m(<=32767);

Output 

对于每一组数据,输出2n个大写字母,‘G’表示好人,‘B’表示坏人,50个字母为一行,不允许出现空白字符。相邻数据间留有一空行。 

Sample 

 InputOutput
2 3
2 4
GBBG

BGGB

 AC代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<vector>
using namespace std;

int main(){
	vector<int>table;
	int n,m;
	while(cin>>n>>m){
		for(int i=0;i<2*n;i++){
			table.push_back(i);
		}
		int pos=0;
		for(int j=0;j<n;j++){
			pos=(pos+m-1)%table.size();
			table.erase(table.begin()+pos);
		}
		int j=0;
		for(int i=0;i<2*n;i++){
			if(i%50==0&&i)cout<<endl;
			if(j<table.size()&&i==table[j]){
				j++;
				cout<<"G";
			}
			else
				cout<<"B";
		}
		cout<<endl<<endl;
		table.clear();
	}
}

 

B - Text Reverse

Ignatius likes to write words in reverse way. Given a single line of text which is written by Ignatius, you should reverse all the words and then output them.

Input 

The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single line with several words. There will be at most 1000 characters in a line. 

Output 

For each test case, you should output the text which is processed. 

Sample 

InputOutput
3
olleh !dlrow
m'I morf .udh
I ekil .mca
hello world!
I'm from hdu.
I like acm.

 Presentation Error代码:感觉没啥错误,但是一直PE

#include<iostream>
#include<vector>	
using namespace std;

int main(){
	vector<char>a;
	char c;
	char b[20000];
	int n;
	cin>>n;
	while(n--){
		while(cin>>b){
			a.clear();
			for(int i=0;i<strlen(b);i++){
				a.push_back(b[i]);
			}
			for(int i=a.size()-1;i>=0;i--){
				cout<<a[i];
			}
			c=getchar();
			if(c=='\n'||c==EOF)  break;
			if(c==' ')cout<<" ";
		}
		cout<<endl;
	}
}

AC代码:(一个一个字符输入可以过)

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<stack>

using namespace std;

int main(){
	int n;
	char a;
	cin>>n;
	getchar();
	while(n--){
		stack<char>s;
		while(true){
			a=getchar();
			if(a==' '||a=='\n'||a==EOF){
				while(!s.empty()){
					cout<<s.top();
					s.pop();
				}
				if(a=='\n'||a==EOF){cout<<endl;break;}
				cout<<" ";
			}
			else
				s.push(a);
		}
	}
}

C - ACboy needs your help again!

ACboy was kidnapped!!
he miss his mother very much and is very scare now.You can't image how dark the room he was put into is, so poor :(.
As a smart ACMer, you want to get ACboy out of the monster's labyrinth.But when you arrive at the gate of the maze, the monste say :" I have heard that you are very clever, but if can't solve my problems, you will die with ACboy."
The problems of the monster is shown on the wall:
Each problem's first line is a integer N(the number of commands), and a word "FIFO" or "FILO".(you are very happy because you know "FIFO" stands for "First In First Out", and "FILO" means "First In Last Out").
and the following N lines, each line is "IN M" or "OUT", (M represent a integer).
and the answer of a problem is a passowrd of a door, so if you want to rescue ACboy, answer the problem carefully! 

Input 

The input contains multiple test cases.
The first line has one integer,represent the number oftest cases.
And the input of each subproblem are described above. 

 Output

For each command "OUT", you should output a integer depend on the word is "FIFO" or "FILO", or a word "None" if you don't have any integer. 

Sample 

InputOutput
4
4 FIFO
IN 1
IN 2
OUT
OUT
4 FILO
IN 1
IN 2
OUT
OUT
5 FIFO
IN 1
IN 2
OUT
OUT
OUT
5 FILO
IN 1
IN 2
OUT
IN 3
OUT
1
2
2
1
1
2
None
2
3

 AC代码:

#include<queue>
#include<stack>
#include<algorithm>
#include<iostream>
#include<string>
using namespace std;

int main(){
	int t,n,a;
	cin>>t;
	while(t--){
		string str1,str2;
		queue<int>q;//重新声名一次自带clear()效果
		stack<int>s;//
		cin>>n>>str1;
		while(n--){
			if(str1=="FIFO"){
				cin>>str2;
				if(str2=="IN"){
					cin>>a;
					q.push(a);
				}
				if(str2=="OUT"){
					if(q.empty())cout<<"None\n";
					else{
						cout<<q.front()<<endl;
						q.pop();
					}
				}
			}
			else{
				cin>>str2;
				if(str2=="IN"){
					cin>>a;
					s.push(a);
				}
				if(str2=="OUT"){
					if(s.empty())cout<<"None\n";
					else{
						cout<<s.top()<<endl;
						s.pop();
					}
				}
			}
		}
	}
	return 0;
}

D - 看病要排队

看病要排队这个是地球人都知道的常识。
不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。

现在就请你帮助医院模拟这个看病过程。 

 Input

输入数据包含多组测试,请处理到文件结束。
每组数据第一行有一个正整数N(0<N<2000)表示发生事件的数目。
接下来有N行分别表示发生的事件。
一共有两种事件:
1:"IN A B",表示有一个拥有优先级B的病人要求医生A诊治。(0<A<=3,0<B<=10)
2:"OUT A",表示医生A进行了一次诊治,诊治完毕后,病人出院。(0<A<=3) 

Output

 对于每个"OUT A"事件,请在一行里面输出被诊治人的编号ID。如果该事件时无病人需要诊治,则输出"EMPTY"。
诊治人的编号ID的定义为:在一组测试中,"IN A B"事件发生第K次时,进来的病人ID即为K。从1开始编号。

Sample 

InputOutput
7
IN 1 1
IN 1 2
OUT 1
OUT 2
IN 2 1
OUT 2
OUT 1
2
IN 1 1
OUT 1
2
EMPTY
3
1
1

 AC代码:

思路:为三个医生创建三个优先队列即可,在结构体内部定义"比较"操作

#include<queue>
#include<algorithm>
#include<iostream>
#include<string>
using namespace std;

struct node{
	int x,y,p;//x为医生号码,y为病人优先级别,p为病人入院序号
	bool operator<(const node & a)const{
		if(y==a.y)return p>a.p;//当优先级一样时,序号由大到小输出,就是所谓的先来后到
		return y<a.y;//优先级由大到小输出(注意此处只是优先队列是这样而已,其他的与此写法相反)
	}
}k;

int main(){
	int t,x,y;
	string a;
	while(cin>>t){
		priority_queue<node>q1;//此处的声明最好写在里面,省去了clear();
		priority_queue<node>q2;//为三个医生创建三个优先队列
		priority_queue<node>q3;
		k.p=0;//刷新序号
		while(t--){
			cin>>a;
			if(a=="IN"){
				cin>>k.x>>k.y;
				if(k.x==1){
					k.p++;
					q1.push(k);
				}
				if(k.x==2){
					k.p++;
					q2.push(k);
				}
				if(k.x==3){
					k.p++;
					q3.push(k);
				}
			}
			if(a=="OUT"){
				cin>>k.x;
				if(k.x==1){
					if(q1.empty())cout<<"EMPTY\n";
					else {
						cout<<q1.top().p<<endl;
						q1.pop();
					}
				}
				if(k.x==2){
					if(q2.empty())cout<<"EMPTY\n";
					else {
						cout<<q2.top().p<<endl;
						q2.pop();
					}
				}
				if(k.x==3){
					if(q3.empty())cout<<"EMPTY\n";
					else{
						cout<<q3.top().p<<endl;
						q3.pop();
					}
				}
			}
		}
	}
}

E - 士兵队列训练问题

某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,继续从头开始进行一至二报数。。。,以后从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。 

 Input

本题有多个测试数据组,第一行为组数N,接着为N行新兵人数,新兵人数不超过5000。 

Output 

共有N行,分别对应输入的新兵人数,每行输出剩下的新兵最初的编号,编号之间有一个空格。 

Sample 

InputOutput
2
20
40
1 7 19
1 19 37

 AC代码:(一开始用的vector)

#include<stdio.h>
#include<iostream>
#include<vector>
using namespace std;

int main(){
	int n,t,p=0;
	vector<int>v;
	cin>>t;

	while(t--){
		cin>>n;
		int a=3;
		for(int i=1;i<=n;i++){
			v.push_back(i);
		}

		while(v.size()>3){

			a==2?a=3:a=2;
			int  flag=1;
			for(int i=1;i<=n;i++){
				if(i%a==0) {
					v.erase(v.begin()+(i-flag));
					flag++;
				}
			}
			p=n/a;
			n=n-p;
		}

		for(int i=0;i<v.size()-1;i++){
			cout<<v[i]<<" ";
		}
		cout<<v[v.size()-1]<<endl;

		v.clear();
	}
}

 后面看到书上写的list,索性又写了一遍

#include<iostream>
#include<list>
using namespace std;

int main(){
	int t,n;
	cin>>t;
	while(t--){
		list<int>mylist;
		list<int>::iterator it;
		int k=2;
		cin>>n;
		for(int i=1;i<=n;i++){
			mylist.push_back(i);
		}
		while(mylist.size()>3){
			int num=1;
			for(it=mylist.begin();it!=mylist.end();){
				if(num++%k==0){
					it=mylist.erase(it);
				}
				else it++;//注意如果erase掉了列表的中间某个元素,会自动将这个元素后面的所有元素前移
			}
			k==2?k=3:k=2;//每次报的数2,3交换
		}
		for(it=mylist.begin();it!=mylist.end();it++){
			if(it!=mylist.begin())cout<<" "<<*it;
			else cout<<*it;
		}
		cout<<endl;
	}
}

 应用场景:

vector:插入和删除操作少,随机访问元素频繁.

list:插入和删除频繁,随机访问较少.


F - 产生冠军

有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。
球赛的规则如下:
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。 

Input

输入含有一些选手群,每群选手都以一个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以一对选手名字(中间隔一空格)表示,前者战胜后者。如果n为0,则表示输入结束。 

Output 

 对于每个选手群,若你判断出产生了冠军,则在一行中输出“Yes”,否则在一行中输出“No”。

Sample 

InputOutput
3
Alice Bob
Smith John
Alice Smith
5
a c
c d
d e
b e
a d
0
Yes
No

 AC代码:

思路:判断所有人的集合和有过失败记录的人的集合是否差一

#include<set>
#include<algorithm>
#include<iostream>
#include<string>
using namespace std;

int main(){
	int n;
	string str1,str2;
	while(cin>>n&&n){
		set<string>s1;
		set<string>s2;
		while(n--){
			cin>>str1>>str2;
			s1.insert(str1);s1.insert(str2);
			s2.insert(str2);
		}
		if(s1.size()-s2.size()==1)cout<<"Yes"<<endl;
		else	cout<<"No"<<endl;

	}
}

G - Shopping

Every girl likes shopping,so does dandelion.Now she finds the shop is increasing the price every day because the Spring Festival is coming .She is fond of a shop which is called "memory". Now she wants to know the rank of this shop's price after the change of everyday. 

Input 

One line contians a number n ( n<=10000),stands for the number of shops.
Then n lines ,each line contains a string (the length is short than 31 and only contains lowercase letters and capital letters.)stands for the name of the shop.
Then a line contians a number m (1<=m<=50),stands for the days .
Then m parts , every parts contians n lines , each line contians a number s and a string p ,stands for this day ,the shop p 's price has increased s. 

Output 

Contains m lines ,In the ith line print a number of the shop "memory" 's rank after the ith day. We define the rank as :If there are t shops' price is higher than the "memory" , than its rank is t+1. 

Sample 

InputOutput
3
memory
kfc
wind
2
49 memory
49 kfc
48 wind
80 kfc
85 wind
83 memory
1
2

 

#include<iostream>
#include<map>
#include<string>
using namespace std;

int main(){
	int n,m,p;
	map<string,int>shop;//注意此处不能写成了map<int,string>shop
	while(cin>>n){
		string s1;
		for(int i=0;i<n;i++)cin>>s1;//此处的输入不要用while(n--),因为后面要用到n
		cin>>m;
		while(m--){
			for(int i=0;i<n;i++){
				cin>>p>>s1;
				shop[s1]+=p;
			}
			int rank=1;
			map<string,int>::iterator it;
			for(it=shop.begin();it!=shop.end();it++){
				if(it->second>shop["memory"])rank++;
			}
			cout<<rank<<endl;
		}	
		shop.clear();
	}
}

H - Ignatius and the Princess II

Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, "I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too." Ignatius says confidently, "OK, at last, I will save the Princess."

"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......"
Can you help Ignatius to solve this problem? 

Input 

 The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub's demand. The input is terminated by the end of file.

Output 

For each test case, you only have to output the sequence satisfied the BEelzebub's demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number. 

Sample 

InputOutput
6 4
11 8
1 2 3 5 6 4
1 2 3 4 5 6 7 9 8 11 10

 AC代码:

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
	int n,m,a[1005];
	while(cin>>n>>m){
		for(int i=1;i<=n;i++){
			a[i]=i;
		}
		int num=1;
		do{
			if(num==m)break;
			num++;
		}while(next_permutation(a+1,a+n+1));
		for(int i=1;i<n;i++){
			cout<<a[i]<<" ";
		}
		cout<<a[n]<<endl;
	}
}

I - 排列2

Ray又对数字的列产生了兴趣:
现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。

Input 

每组数据占一行,代表四张卡片上的数字(0<=数字<=9),如果四张卡片都是0,则输入结束。 

 Output

对每组卡片按从小到大的顺序输出所有能由这四张卡片组成的4位数,千位数字相同的在同一行,同一行中每个四位数间用空格分隔。
每组输出数据间空一行,最后一组数据后面没有空行。 

Sample 

InputOutput
1 2 3 4
1 1 2 3
0 1 2 3
0 0 0 0
1234 1243 1324 1342 1423 1432
2134 2143 2314 2341 2413 2431
3124 3142 3214 3241 3412 3421
4123 4132 4213 4231 4312 4321

1123 1132 1213 1231 1312 1321
2113 2131 2311
3112 3121 3211

1023 1032 1203 1230 1302 1320
2013 2031 2103 2130 2301 2310
3012 3021 3102 3120 3201 3210

思路:和上一题类似,直接用next_permutation即可,需要注意的是输出格式.

 AC代码:

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
	int a[4],flag=0;
	while(true){
		for(int i=0;i<4;i++){
			cin>>a[i];
		}
		if(a[0]==0&&a[1]==0&&a[1]==0&&a[3]==0) break;
		else 
			if(flag==1) cout<<endl;//除第一次输入,以后每次输入换行
		flag=1;
		sort(a,a+4);//排序,得到最小排列
		int b=a[0];//记录第一个元素
		int flag2=0;
		do{
			if(a[0]!=b&&flag2){cout<<endl;flag2=0;}//这一次的第一个元素与上一次排列的第一个元素相比,不同且这一行有输出则换行
			b=a[0];//每次更新第一个元素
			for(int i=0;i<4;i++){
				if(a[0]==0)break;//输出第一个不能为零
				if(flag2==1&&i==0)printf(" ");//上一次没有换行,在每次输出第一个元素之前输出空格
				printf("%d",a[i]);
				flag2=1;
			}
		}while(next_permutation(a,a+4));
		cout<<endl;
	}
}

小船静静往返

马谛斯的海岸

星空下的夜晚

交给梵谷点燃

梦美的太短暂

孟克桥上呐喊

这世上的热闹

出自孤单

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值