GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版
又是一个情况复杂一点的题目。题目要求去掉元素,使剩下的数字最大,实际做法是从原序列中挑选数字,使得挑选后新序列的数字最大。
当原序列中剩余元素可以覆盖整个新序列时,最前面的元素肯定是最大的,即可能为多个9,后面的元素是8, 7等。所以这是一个从前向后越来越小的序列。这里使用第一个map存放,分别记录每个数字的起点和终点。
注意当新的更大的数字放置在对应位置时,新序列后面的位置的数字由于在原序列比这个更大的数字更早,因此不能存在,需要全部删掉。
考虑剩余元素可以不覆盖整个新序列时。如果它在新序列从后向前的位置比在原序列短,即这个元素后面还有冗余位置可以填充,那就走前面可以覆盖的流程即可。
如果它在新序列从后向前的位置比在原序列长,即这个元素如果按照排序填充的话,后面的元素数将会不够,这时候这个元素必然会填充到新序列的位置是:原序列从后向前的位置。且他后面的所有元素都复制到新序列中作为后续元素。这里使用了第二个map记录。
最后输出时,注意第一个map中的数据可能并不是完整的新序列数据,且第二个map是覆盖逻辑,优先级更高,因此这里使用序号遍历,从两个map中分别找。
AC代码
cpp
#include <stdio.h>
#include <map>
#define MAXN 100005
using namespace std;
// beg 起始位置 end 终点的下一个位置
struct Stru
{
int beg, end;
};
char s1[MAXN];
int n, d;
int s2[MAXN];
int s2len;
map<int, Stru> mp;
map<int, int> mp2;
// 调试输出
void outMap()
{
printf("mp:\n");
for (auto ip = mp.begin(); ip != mp.end(); ++ip)
{
printf("i:%d beg:%d end:%d \n", ip->first, ip->second.beg, ip->second.end);
}
printf("mp2:\n");
for (auto ip = mp2.begin(); ip != mp2.end(); ++ip)
{
printf("v:%d i:%d \n", ip->first, ip->second);
}
putchar('\n');
}
// 尾部所有元素一一对应
void setTail(int i)
{
int j;
mp2[s2len - (n - i)] = s1[i];
for (j = i + 1; j < n; ++j)
mp2[s2len - (n - j)] = s1[j];
}
void computed()
{
int i, c1;
for (i = 0; i < n; ++i)
{
if (mp.count(s1[i]))
{
if (s2len - mp[s1[i]].end <= 0)
continue;
if (s2len - mp[s1[i]].end >= n - i)
{
setTail(i);
return;
}
mp[s1[i]].end = mp[s1[i]].end + 1;
for (c1 = s1[i] - 1; c1 >= 0; --c1)
{
if (mp.count(c1))
mp.erase(c1);
}
}
else
{
for (c1 = s1[i] + 1; c1 <= 9; ++c1)
{
if (mp.count(c1))
{
if (s2len - mp[c1].end <= 0)
break;
if (s2len - mp[c1].end >= n - i)
{
setTail(i);
return;
}
mp[s1[i]] = {mp[c1].end, mp[c1].end + 1};
break;
}
}
if (c1 > 9)
{
if (s2len >= n - i)
{
setTail(i);
return;
}
else
mp[s1[i]] = {0, 1};
}
for (c1 = s1[i] - 1; c1 >= 0; --c1)
{
if (mp.count(c1))
mp.erase(c1);
}
}
// printf("-- i: %d \n", i);
// outMap();
}
}
void outputRes()
{
int i, j;
for (i = 0; i < s2len; ++i)
{
if (mp2.count(i))
{
putchar(mp2[i] + '0');
continue;
}
for (j = 9; j >= 0; --j)
{
if (!mp.count(j))
continue;
if (i >= mp[j].beg && i < mp[j].end)
putchar(j + '0');
}
}
putchar('\n');
}
int main()
{
int i;
while (scanf("%d %d", &n, &d) >= 2 && n > 0 && d > 0)
{
scanf("%s", s1);
s2len = n - d;
for (i = 0; i < n; ++i)
s1[i] = s1[i] - '0';
mp.clear();
mp2.clear();
computed();
// outMap();
outputRes();
}
return 0;
}