题目大意:给你一个1000内长度数字让你删掉m个数使得剩下的数值最小
思路:删掉m个数,那么剩下n-m个数。最高为越小,整个数就越小,即使后面再大,比如1999和2000,所以要让小的数在高位。
用RMQ找出整个区间的最小值,然后从最小值右边区间找最小值,然后递归寻找右边区域最小值。
右边区域找完如果还没达到n-m只能找左边的区域最小值。反复递归。比如54123,先找到1,然后再找到2,然后3,然后4,然后5。
找到的数用ans数组记录,最后遍历ans数组输出。
WA了四次;因为长度太长,用了一个int来存输出结果,就WA了
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <string.h>
#define N 1100
using namespace std;
int ans[N],n,m;
struct node
{
int x,i;
} a[N][30];
void RMQ()
{
for(int j = 1; (1<<j) <= n; j++)
for(int i = 1; i+(1<<j)-1 <= n; i++)
if(a[i][j-1].x <= a[i+(1<<(j-1))][j-1].x)
{
a[i][j].x = a[i][j-1].x;//找到最小值,并且存下标
a[i][j].i = a[i][j-1].i;
}
else
{
a[i][j].x = a[i+(1<<(j-1))][j-1].x;
a[i][j].i = a[i+(1<<(j-1))][j-1].i;
}
}
void solve(int l,int r)
{
if(!m || l > r)//如果l>r越界,然会上一层,m==0表示找到所有数
return;
int k = (int)(log10(r-l+1)/log10(2));
int num1 = a[l][k].x;//数字
int num2 = a[r-(1<<k)+1][k].x;
int x1 = a[l][k].i;//数字对应的下标
int x2 = a[r-(1<<k)+1][k].i;
if(num1 <= num2)
{
ans[x1] = a[x1][0].x;//找到区间最小值,把它存入对应下标的ans中
m--;//m减1
solve(x1+1,r);
if(m!=0)//找完右边找左边
solve(l,x1-1);
}
else
{
ans[x2] = a[x2][0].x;
m--;
solve(x2+1,r);
if(m!=0)
solve(l,x2-1);
}
}
int main()
{
char ch[N];
while(~scanf(" %s", ch))
{
memset(ans,-1,sizeof(ans));
memset(a,0,sizeof(a));
scanf("%d", &m);
n = strlen(ch);
m = n - m;//要剩下m个数
if(m <= 0)//如果去掉的数比给的数多 为0
{
cout<<'0'<<endl;
continue;
}
for(int i = 0; i < n; i++)
{
a[i+1][0].x = ch[i] - '0';//a下标从1开始
a[i+1][0].i = i+1;
}
RMQ();
solve(1,n);
int flag = 0;
int i = 1;
while(ans[i] ==0 || ans[i] == -1)
i++;
for(; i <= n; i++)
if(ans[i] != -1)
{
printf("%d",ans[i]);
flag = 1;
}
if(!flag)
cout<<0;
printf("\n");
}
return 0;
}
WA代码:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <string.h>
#define N 1100
using namespace std;
int ans[N],n,m;
struct node
{
int x,i;
} a[N][30];
void RMQ()
{
for(int j = 1; (1<<j) <= n; j++)
for(int i = 1; i+(1<<j)-1 <= n; i++)
if(a[i][j-1].x <= a[i+(1<<(j-1))][j-1].x)
{
a[i][j].x = a[i][j-1].x;//找到最小值,并且存下标
a[i][j].i = a[i][j-1].i;
}
else
{
a[i][j].x = a[i+(1<<(j-1))][j-1].x;
a[i][j].i = a[i+(1<<(j-1))][j-1].i;
}
}
void solve(int l,int r)
{
if(!m || l > r)//如果l>r越界,然会上一层,m==0表示找到所有数
return;
int k = (int)(log10(r-l+1)/log10(2));
int num1 = a[l][k].x;//数字
int num2 = a[r-(1<<k)+1][k].x;
int x1 = a[l][k].i;//数字对应的下标
int x2 = a[r-(1<<k)+1][k].i;
if(num1 <= num2)
{
ans[x1] = a[x1][0].x;//找到区间最小值,把它存入对应下标的ans中
m--;//m减1
solve(x1+1,r);
if(m!=0)//找完右边找左边
solve(l,x1-1);
}
else
{
ans[x2] = a[x2][0].x;
m--;
solve(x2+1,r);
if(m!=0)
solve(l,x2-1);
}
}
int main()
{
char ch[N];
while(~scanf(" %s", ch))
{
memset(ans,-1,sizeof(ans));
memset(a,0,sizeof(a));
scanf("%d", &m);
n = strlen(ch);
m = n - m;//要剩下m个数
if(m <= 0)//如果去掉的数比给的数多 为0
{
cout<<'0'<<endl;
continue;
}
for(int i = 0; i < n; i++)
{
a[i+1][0].x = ch[i] - '0';//a下标从1开始
a[i+1][0].i = i+1;
}
RMQ();
solve(1,n);
//WA
int num = 0;
for(int i = 1; i <= n; i++)
if(ans[i] != -1)
num = num*10 + ans[i];
printf("%d\n",num);
}
return 0;
}