HDU 3183 RMQ(指定区间的最值)
题意很简单,自己好好读一下。
因为留下来的数要构成最小的数,所以我们可以先找字段里面最小的数字,
比如样例 a=178534 4 ;也就是说我们需要按顺序找到3个最小数,比如找第一个小的数,只能在a[0]...a[3]中找,第二个小的数,只能在a[1]...a[4]中找,诸如这样的找法一直找到所有需要找的数。
刚开始我是这样写的;
#include<bits/stdc++.h>
using namespace std;
struct node
{
int x;
int d;
};
node a[1010];
int m;
char ch[1010];
int main()
{
while(scanf("%s ",ch)!=EOF)
{
scanf("%d",&m);
int len=strlen(ch);
for(int i=0; i<len; i++)
{
a[i].x=ch[i]-'0';
a[i].d=0;
}
int dd=len-m;
int b[1010];
for(int i=0; i<dd; i++)
{
int mm=99999,flag;
for(int j=i; j<i+m+1; j++)
{
if(a[j].x<mm && !a[j].d)
{
mm=a[j].x;
flag=j;
}
}
a[flag].d=1;
b[i]=mm;
}
int ans=0;
for(int i=0; i<dd; i++)
{
ans=ans*10+b[i];
}
cout<<ans<<endl;
}
return 0;
}
但是这样的弊端就是,有可能找到的数字的顺序是不对的,刚开始没意识到,也是今天晚上打cf之前想到的;
这是ST(就是个动态规划的思想)的解法,只有理解了RMQ的f[i][j]跳转的方式和意义,就能很好的应用了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f3f
char a[1010],num[1010];
int len,n;
int f[1010][15];
int Min(int i,int j)
{
return a[i]<=a[j]?i:j;
}
void RMQ(int n)
{
for(int i=0; i<n; i++)
f[i][0]=i;
for(int j=1; j<=(int)(log(1.0*n)/log(2.0)); j++)
{
for(int i=0; i+(1<<j)-1<n; i++)
{
f[i][j]=Min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
int qq(int l,int r)
{
int x=(int)(log(1.0*(r-l+1))/log(2.0));
return Min(f[l][x],f[r-(1<<x)+1][x]);
}
int main()
{
while(scanf("%s ",a)!=EOF)
{
scanf("%d",&n);
len=strlen(a);
RMQ(len);
n=len-n;
int i=0,j=0;
while(n--)
{
i=qq(i,len-n-1);
num[j++]=a[i++];
}
for(i=0; i<j; i++)
if(num[i]!='0')
break;
if(i==j)
{
printf("0\n");
continue;
}
else
{
for( ;i<j; i++)
printf("%c",num[i]);
}
printf("\n");
}
return 0;
}