题目描述
有一十进制正整数,移除其中的 K 个数,使剩下的数字是所有可能中最大的。
假设:
字符串的长度一定大于等于 K
字符串不会以 0 开头
输入描述:

一行由正整数组成的数字字符串,和一个正整数 K,两个数据用空格隔开,如:1432219 3。
字符串长度不超过2000,K<=2000。

输出描述:

移除 K 位后可能的最大的数字字符串。
1432219移除 1, 2, 1这 3 个数字后得到 432,为所有可能中的最大值。

示例1
输入
复制

1432219 3

输出
复制

4329

可以发现 :

  1. 一个数字数组可以划分成很多个子数组,这些子数组可能单调增 单调减 或者平滑不变
  2. 如果这个数 n u m = 12349685 num=12349685 num=12349685递增子数组开头,则只要还可以删除数字,删开头一定最优
  3. 如果这个数 n u m = 43217892 num=43217892 num=43217892递减子数组开头,且能删的个数小于4,则开头一定不能删
    应该删除 321 321 321则三个数
  4. 只要还能删,我们就必须留下最长单调减序列,一定是最优答案

考虑单调栈(看别人的代码才知道的,一开始考虑贪心自闭了很久)

  • 只要当前数字 n u m [ i ] num[i] num[i]比栈顶大,并且还能删除,则删除栈顶,并把 n u m [ i ] num[i] num[i]入栈
  • f o r for for完整个数字数组还有可以删除的个数 k k k,则进行 k k k弹栈
  • 最后 , 把栈内的数字翻转 r e v e r s e reverse reverse就是答案
//设数字为24593215
//如果[0,K]是递增的,删掉[0,cnt(cnt<K)]会使得答案增大
//找到所有递增序列,删掉

string str;
cin >> str >> K;
stack<char> stk;
for(auto ch : str) { //把每个数字和栈顶比较
	while(stk.size() && stk.top() < ch && K) { //只要还能删除 且 栈顶小于num[i]就退栈
		stk.pop();
		K --;
	}
	stk.push(ch); //num[i]入栈
}
string ans;
while(K--) { //删到最后还能删,继续退栈
	stk.pop();
}
while(!stk.empty()) {
	ans.push_back(stk.top());
	stk.pop();
}
reverse(ans.begin(), ans.end()); //记得翻转
cout << ans << endl;

完整代码

#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif

#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>

#define MAXN ((int)1e5+7)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;

#define show(x...) \ do { \ cout << "\033[31;1m " << #x << " -> "; \ err(x); \ } while (0)

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO{

	char print_f[105];
	void read() {}
	void print() { putchar('\n'); }

	template <typename T, typename... T2>
		inline void read(T &x, T2 &... oth) {
			x = 0;
			char ch = getchar();
			ll f = 1;
			while (!isdigit(ch)) {
				if (ch == '-') f *= -1; 
				ch = getchar();
			}
			while (isdigit(ch)) {
				x = x * 10 + ch - 48;
				ch = getchar();
			}
			x *= f;
			read(oth...);
		}
	template <typename T, typename... T2>
		inline void print(T x, T2... oth) {
			ll p3=-1;
			if(x<0) putchar('-'), x=-x;
			do{
				print_f[++p3] = x%10 + 48;
			} while(x/=10);
			while(p3>=0) putchar(print_f[p3--]);
			putchar(' ');
			print(oth...);
		}
} // namespace FastIO
using FastIO::print;
using FastIO::read;

int n, m, Q, K;
bool up[MAXN], vis[MAXN];

int main() {
#ifdef debug
	freopen("test", "r", stdin);
	clock_t stime = clock();
#endif
	//设数字为24593215
	//如果[0,K]是递增的,删掉[0,cnt(cnt<K)]会使得答案增大
	//找到所有递增序列,删掉

	string str;
	cin >> str >> K;
	stack<char> stk;
	for(auto ch : str) {
		while(stk.size() && stk.top() < ch && K) {
			stk.pop();
			K --;
		}
		stk.push(ch);
	}
	string ans;
	while(K--) {
		stk.pop();
	}
	while(!stk.empty()) {
		ans.push_back(stk.top());
		stk.pop();
	}
	reverse(ans.begin(), ans.end());
	cout << ans << endl;

#ifdef debug
	clock_t etime = clock();
	printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif 
	return 0;
}