第一种做法是贪心做法,只要前面的数比后面的大就把他删掉,这种做法是正确的,也比较好理解,这里就不说了,我比较想说一下ST算法,RMQ的应用
主要是返回数组的下标,RMQ要改成<=(这里是个坑点,取连续数是可以的),他的转移方程为x = dp[i-1][j],y = dp[i-1][j+1<<(i-1)];
dp[i][j] = a[x] <= a[y] ? x : y; 这里既是转化为取n-m个数,首先在1 ~ m+1中必然选一个数,所以这个数就是n-m数中第一个数,记录所选的位置id,下次便是id+1,m++;
m++ = id + m + 1 - (id - 1),反证法可以很好的证明上述结论,稍微有点难想,如此看来,dp[i][j]将返回i 到 i+2<<j-1的最小值的下标;
说到这里我们应该感受到了,重要的是理解选数的过程,RMQ只是个优化...这个思维过程还是希望读者好好体会一下的.
#include<cstdio> #include<cstring> #include<cmath> char s[1010]; char ans[1020]; int st[1010][20]; int Min(int x,int y) { return s[x] <= s[y] ? x : y; } void RMQ_Init(int len) { for(int i = 0; i < len; i++) st[i][0] = i; for(int j = 1; (1<<j) < len; j++) for(int i = 0; i+(1<<j)-1 < len;i++) st[i][j] = Min(st[i][j-1],st[i+(1<<(j-1))][j-1]); } int Query(int l,int r) { int k = (int)(log((double)(r-l+1))/log(2.0)); return Min(st[l][k],st[r-(1<<k)+1][k]); } int main() { int len, m, i; while(scanf("%s%d",s, &m)!=EOF) { len = strlen(s); RMQ_Init(len); m = len - m; int pos = 0, num = 0; while(m--) { pos = Query(pos, len - m - 1); ans[num++] = s[pos++]; } for(i = 0; i < num; i++) if(ans[i]!=‘0‘) break; if(i == num) printf("0"); else { while(i < num) printf("%c",ans[i++]); } puts(""); } return 0; }
时间: 2024-12-20 22:54:57