题号:NC15029
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
小鱼儿吐泡泡,嘟嘟嘟冒出来。小鱼儿会吐出两种泡泡:大泡泡"O",小泡泡"o"。 两个相邻的小泡泡会融成一个大泡泡,两个相邻的大泡泡会爆掉。 (是的你没看错,小气泡和大气泡不会产生任何变化的,原因我也不知道。) 例如:ooOOoooO经过一段时间以后会变成oO。
输入描述:
数据有多组,处理到文件结束。 每组输入包含一行仅有'O'与'o'组成的字符串。
输出描述:
每组输出仅包含一行,输出一行字符串代表小鱼儿吐出的泡泡经过融合以后所剩余的泡泡。
示例1
输入
复制ooOOoooO
ooOOoooO
输出
复制oO
oO
说明
自左到右进行合并
备注:
对于100%的数据, 字符串的长度不超过100。
解题思路:
题意:从左到右,如果是两个小泡泡则变为一个大泡泡,如果是两个大泡泡则爆炸。所以可以利用栈的先进后出的原则,遍历字符串,根据题意运行。
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
string s;
int main() {
while (cin >> s) {
stack<char>res;
int lentos = s.length();
res.push(s[0]);
for (int i = 1; i < lentos; i++) {
// if(res.empty() || res.top()!=s[i]) res.push(s[i]); // 栈空入栈 || 一大一小气泡
// 栈不为空分三个情况,1.两个小气泡,2.两个大气泡,3.一大一小
if (!res.empty() && res.top() == s[i] && s[i] == 'o') { // 两个小气泡
res.pop();
char ch = 'O';
if (!res.empty() && res.top() == ch) res.pop();
else if (res.empty() || res.top() != ch)res.push(ch);
continue;
}
if (!res.empty() && res.top() == s[i] && s[i] == 'O') { // 两个大气泡
res.pop();
continue;
}
if (!res.empty() && res.top() != s[i]) { // 两个不同的气泡
char ch = s[i + 1];
if (ch == s[i]) {
i++;
if (ch == 'O') { // 后两个都为大泡泡
continue;
} else ch = 'O'; // 后面两个都为小泡泡
if (!res.empty() && res.top() == ch && ch == 'O') { // 两个大气泡
res.pop();
continue;
}
}
}
res.push(s[i]);
}
int len = res.size();
string res2;
for (int i = 0; i < len; i++) {
res2[i] = res.top();
res.pop();
}
for (int i = len - 1; i >= 0; i--)
cout << res2[i];
cout << endl;
}
}
题号:NC14326
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
The local tradition is that every train arriving from the direction A continues in the direction B with coaches reorganized in some way. Assume that the train arriving from the direction A has N <= 1000 coaches numbered in increasing order 1, 2, ..., N. The chief for train reorganizations must know whether it is possible to marshal coaches continuing in the direction B so that their order will be a1, a2, ..., aN. Help him and write a program that decides whether it is possible to get the required order of coaches. You can assume that single coaches can be disconnected from the train before they enter the station and that they can move themselves until they are on the track in the direction B. You can also suppose that at any time there can be located as many coaches as necessary in the station. But once a coach has entered the station it cannot return to the track in the direction A and also once it has left the station in the direction B it cannot return back to the station.
Input
The input consists of blocks of lines. Each block except the last describes one train and possibly more requirements for its reorganization. In the first line of the block there is the integer N described above. In each of the next lines of the block there is a permutation of 1, 2, ..., N. The last line of the block contains just 0.
The last block consists of just one line containing 0.
输入描述:
The input consists of blocks of lines. Each block except the last describes one train and possibly more requirements for its reorganization. In the first line of the block there is the integer N described above. In each of the next lines of the block there is a permutation of 1, 2, ..., N. The last line of the block contains just 0. The last block consists of just one line containing 0.
输出描述:
The output contains the lines corresponding to the lines with permutations in the input. A line of the output contains Yes if it is possible to marshal the coaches in the order required on the corresponding line of the input. Otherwise it contains No. In addition, there is one empty line after the lines corresponding to one block of the input. There is no line in the output corresponding to the last ``null'' block of the input.
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
int n;
int main() {
while (cin >> n && n) {
int x;
while (cin >> x && x) { // 因为 0 的时候表示结束
vector<int>target; // 存目标序号
target.push_back(x); // 先存放第一个元素,是为了上面特判是否为 0
for (int i = 1; i < n; i++) { // 剩下的元素依次存入
cin >> x;
target.push_back(x);
}
stack<int>res; // 栈
int k = 0; // 记录删除的次数,如果k==n则符合题意
for (int i = 1; i <= n; i++) { // 共n个数,序号则是 1 - > n
res.push(i);
while (!res.empty() and res.top() == target[k]) { //栈不为空,且满足题意则删除一个
if (!res.empty()) { k++; res.pop(); } // k负责记录删除的次数
}
}
if (k == n) cout << "Yes" << endl; // 删除的次数正好为n,显然满足题意
else cout << "No" << endl;
}
cout << endl;
}
return 0;
}
题号:NC14666
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
M国的地势高低不平,现给出一个数组代表此国家某纬度上均匀分布的N座山的海拔高度H[i](任意两座山高度不同),已知每座山的山顶上都有一座哨塔,若两个哨兵分别位于第i、j(i<j)座山上,当且仅当两人所在的山比两人之间所有的山都高
时,这两个哨兵可以相互监视,M国的防守能力大小为相互监视的哨兵对数。H国早已对M国虎视眈眈,H国的皇帝希望黑魔法师们可以在M国的某两座山之间放置一块巨大的屏障,M国的哨兵不可通过该屏障互相监视。皇帝想让你告诉他最优的屏障放置位置,你是皇帝手下最信任的军师,现在需要你帮助皇帝计算最优的屏障放置位置和最大的防守力减少量。
输入描述:
第一行包含一个正整数T(T≤20)。
对于每组数据,第一行包含一个正整数n(2≤n≤50000)。
接下来n个不同的正整数,H1,H2,H3,…,Hn(0≤Hi≤109)分别代表横截面上每座山的海拔高度。
(读入数据比较大,建议使用scanf而不要使用cin读入)
对于60%的数据,n≤500
对于80%的数据,n≤5000
对于100%的数据,n≤50000
输出描述:
每组数据输出一行形如“Case #N: X C”,N代表当前是第N组数据(从1开始),X代表屏障放置在第X座山前可使M国的防守能力下降最多, 此时减少量为C。若有多种方案使得减少量为C,那么输出最小的X对应的方案。
示例1
输入
复制2 3 2 1 3 5 4 5 2 6 3
2 3 2 1 3 5 4 5 2 6 3
输出
复制Case #1: 2 2 Case #2: 3 2
Case #1: 2 2 Case #2: 3 2
解题思路:
首先,在i位置加上了屏障后,分割出来的两段不相互影响,所以此时王国的防护能力减少量等于未加屏障时防护能力—两段防护能力。用这种方法求防护能力减少量是因为用下面的方法求每段防护能力较为方便。
方法:由于满足题意的i,j能相互看见,并且i,j的位置相互对称,也就是说i能看见j,j也能看见i,所以我们计算一方看见另一方就可以了,这样我们就可以调整计算顺序,我们可以试着求从左往右看的情况,由于往左看的时候只能看到比自己矮的山,并且由于自身比他们高,其他后续的山是看不到的,所以他们被看完就毫无作用了,这种模式可以用单调栈来处理,栈内元素从栈底到栈顶根据刚才的描述应该是逐渐减少的,,每次入栈时维护但单调栈的性质,维护时出栈的元素个数为当前元素能看见山的个数,最后我们要求的是刚刚对于每个元素所求的数量和。由于这种区间和我们要求好几次,所以想到用前缀和。
加上屏障之后若我们只计算过从右往左看的前缀和,那么我们只能得到屏障左半段的前缀和,但是右半段由于前缀和受到左半段元素的影响不能计算独立的右半段,所以我们还要计算从左往右看的前缀和,这样就能计算右半锻的防护能力,而不受到左半段元素的影响。
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
const int maxn=50005;
int a[maxn],v[maxn],vis[maxn];
int main(){
//freopen("qwe.txt","r",stdin);
int T,cs,n;
scanf("%d",&T);
stack<int > q;
int t = 1;
while(T--)
{
cs++;
memset(v,0,sizeof(v));
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
//“正向遍历判断”,即从头到尾然后利用栈的特性,记录每点(山)向前看过去
// 一直到看到比当前山高的山或找到了了尽头
while(!q.empty()) q.pop();//每次使用栈时都要进行清空的操作
for(int i=1;i<=n;i++)
{
int tmp=0;
vis[i]=vis[i-1];//每个山的初始值都设为前一个山的防御值
//这样vis数组存储的就是前i个山的防御值的总和
while(!q.empty()&&q.top()<a[i])
{
//向前遍历直到高山或尽头
q.pop();
tmp++;
}
if(!q.empty())
vis[i]+=tmp+1;//栈中有山即表示找到的是高山防御值要加一
else vis[i]+=tmp;//找到的是尽头
//这样最终每个vis[i]存储的就是前i个山的防御值
q.push(a[i]);
}
while(!q.empty()) q.pop();
//下面是“逆向遍历判断”,即从尾到头的遍历,记录的是从当前山向后看过去
//一直到比当前高的山或尽头
for(int i=n;i>=1;i--)
{
int tmp=0;
v[i]=v[i+1];//同样每个山的初始值都为后一个山的防御值
//这样v[i]表示的就是从i个山到最后的山的总防御和
while(!q.empty()&&q.top()<a[i])
{
tmp++;
q.pop();
}
if(!q.empty())v[i]+=tmp+1;
else v[i]+=tmp;
q.push(a[i]);
}
int maxnn=-1,id=0;
for(int i=1;i<n;i++)
{
if(v[1]-(vis[i]+v[i+1])>maxnn)
{
//这一步判断可以这样理解
// 首先vis[n]和v[1]的意义是一样的都是总防御值
//下面语句可以这样理解vis[n]-vis[i]=v[i]的即总防御值先去i山的正向遍历防御
//和等于当前山的逆向遍历防御和
//=v[i]-v[i+1]即为i山的去除初始值的防御和
maxnn=vis[n]-(vis[i]+v[i+1]);
id=i;
}
}
printf("Case #%d: %d %d\n",t,id+1,maxnn);
++t;
}
return 0;
}