1. 程式人生 > >A Magic Lamp HDU

A Magic Lamp HDU

題意

給定長度為n位的數字,刪去其中的m位數,不能改變數的順序,使剩下的數最小(如果剩下的數包含前導零輸出時則去掉)。

思路

此題是以所存最小數的位置(下標)進行預處理  

最後輸出的是一個(n-m)位的數,輸出結果的第一位數最大的可選範圍為原數的 0~m(所存n位數的下標)位,一共進行 n-m 次選擇,每次選出最小的那個數的下標,最後一次選擇的右區間正好為 n-1 (0~n-1 一共n位)。假設第一次選出數的下標為 pos (0~m),則下一次從pos+1(pos+1~m+1)開始選則 。都為閉區間。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
char s[1010],pre[1010];
int dp[1010][11];
int n,m;
int minx(int x,int y)   //返回的是最小數的下標
{
    return s[x]<=s[y]?x:y;
}
void rmq()
{
    for(int i=0;i<n;i++)
        dp[i][0]=i;
    for(int j=1;1<<j<n;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
            dp[i][j]=minx(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int query(int l,int r)
{
    int k=(int)(log(r-l+1.0)/log(2.0));
    return minx(dp[l][k],dp[r-(1<<k)+1][k]);
}
int main()
{
    while(~scanf("%s%d",s,&m))
    {
        n=strlen(s);
        rmq();
        int pos=0;
        int i,j;
        for(i=0;i<n-m;i++)
        {
            pos=query(pos,m+i);
            pre[i]=s[pos++];  //將最小數存到pre[]中,並讓pos+1
        }
        for(j=0;j<i;j++)    //判斷前導零
            if(pre[j]!='0')
                break;
        if(j==i)
            printf("0\n");
        else
        {
            for(int k=j;k<i;k++)
                printf("%c",pre[k]);
            printf("\n");
        }
    }
    return 0;
}