Problem Description
小艾和小牛在上数学课的时候觉得非常的无聊,于是他们想出了一个新的游戏,小牛写下N位的数字,小艾的任务
就是在去除了K位后得到一个最大的数。
Input
输入有多组数据。第一行输入一个N和一个K( 1 <= K < N <= 500 000 ).
接下来就是N位数字,确保输入数据中没有前导0。
Output
输出去除了K位后的最大数字。
Sample Input
4 2
1924
7 3
1231234
10 4
4177252841
Sample Output
Source
2012暑假集训
//昨天做的hut(湖南工业吧)挂的一个比赛!感觉题目还是可以的。切了3到水模拟和4道思维题。还有4道太难了
都没人动。感觉这套题里面的思维题很有Topcode的味道,前提是在紧张的时间内做。
//本题就是数字思维题!要想去掉k位数字后得到的数字最大,就要使序列中较大的数字尽量往左移(但并不是
单纯的去掉序列中最小的k位,如6189921569这样10位数去掉5位得到的最大值是99569而不是单纯去掉最小k位
后的89969)。所以就当前num[i]而言我们要去掉前面所有比他小的数字最好,而后面的暂时不管。
以
4177252841为例,要想去掉4个数后得到最大值,从左往右看4、1是下降的,而7上升并且比4、1都大,
那么应该把4、1都 去掉这样7往左移两位整体数据就大了。继续往右扫描,7、2是下降的而到5(5前面有2更小)
就要把2去掉。后5、2、8中出现8比前面都大则要去掉前面小(从小到大去)的。最后满足k位即可。
所以本题可以利用优先队列维护当前num[i]前的序列,从i-n扫描每一位数,每次去掉num[i]前面比它小的数,
这样可以令序列一直处于单调递减状态,最后扫描完后如果还不到k维,则直接从队列中一位位去掉即可,
因为扫描完一遍后序列已经具有单调性。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 500050
struct node
{
int a,ti;
friend bool operator<(node n1,node n2)
{
if(n1.a!=n2.a) return n1.a>n2.a;
else return n1.ti>n2.ti;
}
};
char str[maxn];
int num[maxn];
bool used[maxn];
int main()
{
int n,k,i,j;
priority_queue<node>q;
while(~scanf("%d%d",&n,&k))
{
while(!q.empty())
q.pop();
memset(used,false,sizeof(used));
scanf("%s",str+1);
for(i=1;i<=n;i++)
num[i]=str[i]-'0';
node tp,cnt;
for(i=1;i<=n;i++)
{
while(k>0&&!q.empty()) //去掉前面比当前num[i]小的数
{
cnt=q.top();
if(cnt.a<num[i])
{
q.pop();
used[cnt.ti]=true;
k--;
}
else
break;
}
tp.a=num[i],tp.ti=i;
q.push(tp);
}
while(k>0&&!q.empty())
{
tp=q.top();
q.pop();
used[tp.ti]=true;
k--;
}
for(i=1;i<=n;i++)
if(!used[i])
printf("%d",num[i]);
puts("");
}
return 0;
}