1.题目
SGU - 271
There is a pile of N books on the table. Two types of operations are performed over this pile:
- a book is added to the top of the pile,
- top K books are rotated. If there are less than K books on the table, the whole pile is rotated.
First operation is denoted as ADD(S) where S is the name of the book, and the second operations is denoted as ROTATE.
The maximum number of books is no more than 40000. All book names are non-empty sequences of no more than 3 capital Latin letters. The names of the books can be non-unique.
Input
The first line of input file contains 3 integer numbers N, M, K (0 <= N <= 40000; 0 <= M <= 100000; 0 <= K <= 40000). The following N lines are the names of the books in the pile before performing any operations. The book names are given in order from top book to bottom. Each of the following M lines contains the operation description.
Output
Output the sequence of books names in the pile after performing all operations. First line corresponds to the top book.
Sample test(s)
Input
2 3 2
A
B
ADD©
ROTATE
ADD(D)
Output
D
A
C
B
Author: Michael R. Mirzayanov
Resource: ACM ICPC 2004-2005, NEERC, Southern Subregional Contest
Date: Saratov, October 7, 2004
2.题目大意
一开始桌子上从上到下放着N本书,有M组操作:
1.将前K本书翻转。
2.在头上加一本书。最后输出书的顺序。
3.解题思路
把前k本书在双端队列Q中进行维护,后k本书在另外一个队列q中放置。
当是ADD操作时,根据此时翻转的情况,看把书是加入底部还是顶部。
当是ROTATE操作时,记录翻转的次数。其中根据翻转的次数来决定ADD
的操作和最后的输出,时间效率会比较好,每一个ROTATE操作都进行
倒置操作的模拟的话,显然是不符合时间限制的。
4.双端队列
#include <queue>//必要的头文件
deque<string>Q; //定义一个双端队列Q
Q.push_back(e);//将某元素e放进Q的底部
Q.push_front(s);//将某元素s放进Q的顶部
Q.size();//双端队列中元素的个数
Q.pop_front();//顶部元素释放
Q.pop_back();//底部元素释放
AC代码
#include <iostream>
#include <queue>
#include<string>
#include<cstdio>
using namespace std;
int main()
{
int n, m, k, a =0; cin>>n>>m>>k;
//双端队列,两端都可以进入
deque<string>Q; //前k本需要翻转的书
deque<string>q;//之后不用翻转的书
for( int i = 1; i <= n; i++)
{
string e;
cin>>e;
if(i <= k) Q.push_back(e); //Q内先放进去的是会被翻转的
else q.push_back(e); //q内放进去的是不会被翻转的
}
for(int i = 1; i <= m; i++)
{
char ch[20];
scanf("%s",ch);
if(ch[0] == 'A') //说明是在顶部加了一本书
{
int t = 0;//因为书的名字可能是A,AA,AAA
if(ch[5] == ')' ) t = 4; //类似A
else if(ch[6] == ')' ) t = 5;//类似AA
else t = 6;//类似AAA
string s;
for(int j =4; j<=t; j++ )
s+=ch[j];//把这本书的名字放在string的s中
if(a%2 == 0) Q.push_front(s); //第一次进来从头上进,翻转两次后同理
else Q.push_back(s); // 翻转了一次后从尾部进
if(Q.size() > k)//如果Q中的书已经大于k值了,就说明当前最下面的那本书要拿开
{
if(a % 2 == 0) //第一次,或者翻转两次了之后,是最开始进来的状态
{
q.push_front(Q.back());//把Q中的最后一本书放进q中
Q.pop_back();//把这本书从Q中移开
}
else//翻转了一次之后,相当于最初状态的倒置
{
q.push_front(Q.front());//此时原本在顶部的书在最底部,把它放进q中
Q.pop_front();//移开
}
}
}
if(ch[0] == 'R')
{
a +=1;
}
}
if(a % 2 == 0 ) //说明是跟刚初始时放置状态一样
{ //可以从头开始释放
while(Q.size() > 0)
{
cout<<Q.front()<< endl;
Q.pop_front();
}
}
else//说明是初始状态的倒置
{
while(Q.size()>0)//从尾部开始释放
{
cout<<Q.back()<<endl;
Q.pop_back();
}
}
while(q.size()>0)//如果在这个队列中还有,那么从头开始释放就是。
{
cout<<q.front()<<endl;
q.pop_front();
}
return 0;
}