题意:给你一个共n位的数,让你删除其中的m个位,而且不改变原来数位的顺序,使得余下的数位组成的数最小!
分析:大多数人看到标题上的鸽巢原理肯定会疑惑,鸽巢原理是什么屌定理!然后仔细一看必然大失所望,原来鸽巢原理就是抽屉原理。其实这里是巧用了抽屉原理。
我们不妨反过来考虑,要删除m个位,就相当于要保留n-m个位使得组成的数最小,然后就是使得这个数第i(1,2,3,4,5,......)位最小,而且因为先后顺序不能改变(如果可以改变,那么这题就变成排序题了),那么我们先只能先考察第一个数位。我们显然发现第一个数位只能是在给定数位的第1个到第m+1个中的最小数位值的那个,不妨设取得的数位是第k个,那么第二个数位只能在给定数位的第k+1个到第m+2个之中,之后以此类推!最后把前置0去掉就AC了!
话说RMQ问题的ST算法真是好啊!
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 1000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IT iterator
typedef long long ll;
const double eps = 1e-9;
const double pi = acos(-1);
const ll mod = 1e9+7;
char str[maxn];
char ans[maxn];
int minn[maxn][10];
int min(int i,int j)
{
return str[i]<=str[j]?i:j;
}
void rmq(int n)
{
clr(minn,0x3f3f3f3f);
for(int i=0;i<n;i++)
minn[i][0]=i;
for(int j=1;j<10;j++)
for(int i=0;i<n&&i+(1<<j)-1<n;i++)
minn[i][j]=min(minn[i][j-1],minn[i+(1<<j-1)][j-1]);
}
int query(int l,int r)
{
int k=(int)(log(r-l+1.0)/log(2.0));
return min(minn[l][k],minn[r-(1<<k)+1][k]);
}
int main()
{
int m;
while(~scanf("%s %d",str,&m))
{
int n=strlen(str);
rmq(n);
int ll=-1,M=m;
int len=n-m;
for(int i=0;i<len;i++,M++)
{
ll=query(ll+1,M);
ans[i]=str[ll];
}
int kk=0;
while(ans[kk]=='0'&&kk<len)
kk++;
if(kk==len)
{
puts("0");
continue;
}
for(;kk<len;kk++)
printf("%c",ans[kk]);
puts("");
}
return 0;
}