Petya recieved a gift of a string s with length up to 105 characters for his birthday. He took two more empty strings t and u and decided to play a game. This game has two possible moves:
- Extract the first character of s and append t with this character.
- Extract the last character of t and append u with this character.
Petya wants to get strings s and t empty and string u lexicographically minimal.
You should write a program that will help Petya win the game.
题意为给你一个序列,操作1为把字符串s的第一个字母放在字符串t的尾部,操作2为把t的尾部字母放在u的尾部。现在要求这样操作完下来,字典序最小的u。
首先我们会很容易的发现t就是一个栈,根据先进后出的原则,我们可以想到一种贪心策略:当栈顶元素后面没有比它小的了,就把它pop出来,放在u里。现在问题就转化成了,如果求第i位以后最小的字符,这个就是一个小递推了。我们用dp[i]表示到达第
i位后面最小的元素。由于是算的后面,所以需要使用倒推,也很容易想到方程为dp[i]=min(dp[i+1],s[i]);即当前位及以后的最小,是他下一位最小,或者就是它自己。
这样求出来之后就可以进行模拟,每次发现栈顶是现在后面最小的时就pop出来,最后如果还有残余,就只能按顺序pop了。
下附AC代码。
#include<iostream>
#include<stack>
#include<string.h>
#define maxn 100005
using namespace std;
string s;
stack<char> st;
char dp[maxn];
int main()
{
cin>>s;
char p='z'+1;
dp[s.size()]=p;
for(int i=s.size()-1;i>=0;i--)
{
dp[i]=min(dp[i+1],s[i]);
}
for(int i=0;i<s.size();i++)
{
char temp=s[i];
if(dp[i]<s[i])
{
st.push(s[i]);
}
else
{
cout<<s[i];
while(!st.empty())
{
char now=st.top();
if(dp[i+1]>=now)
{
st.pop();
cout<<now;
}
else
break;
}
}
}
while(!st.empty())
{
char now=st.top();
st.pop();
cout<<now;
}
}