题意:
给出一个n位数,删除m位,使得剩下的数最小
题解:
老师上课讲贪心的时候,说过删1位的情况。贪心策略如下:
对于n位数构成的数删m位,每次总这样删除a[i]:它是第一个满足a[i]>a[i+1]的,如果不存在就删除a[n]。比如176832,删7。假设删其他的这个7在那里碍事都不会使得有更小的情况。删除m位就依次这样删除。贪心+双向链表可以完成删除。
但是可以删m位可以转换为RMQ问题来写。删m位,剩下n-m位。所以原数的第一位到m+1位的数字中最小的那位(记为i位)肯定是n-m位数的第一位。然后再从i+1位到m+2位中找最小的那位作为第二位,依次类推,找够n-m位。
因为这样推的过程中一个推了m次,所以可以删除m次,结合贪心策略可以保证最优解!只不过这里的min函数要修改一下。看代码
#include<bits/stdc++.h>using namespace std;const int maxn = 1111;struct node
{int v;int from, to;
} ns[maxn];void del(int i)
{int from = ns[i].from;int to = ns[i].to;ns[from].to = to;ns[to].from = from;
}
char s[maxn];
int main()
{int m;while(~scanf("%s%d",&s,&m)){int n=strlen(s);for(int i=1; i<=n; i++){ns[i].v = s[i-1]-'0';ns[i].from = i-1;ns[i].to = i+1;}ns[0].to =1;ns[n+1].from = n;int p=0;while(m--){while(ns[p].to!=n+1 && ns[ns[p].to].v>=ns[p].v)p = ns[p].to;del(p);p=ns[p].from;}p=ns[0].to;while(p!=n+1 && ns[p].v==0)p=ns[p].to;if(p==n+1){cout<<0;}else{while(p!=n+1){cout<<ns[p].v;p=ns[p].to;}}puts("");}
}
#include<bits/stdc++.h>using namespace std;const int maxn = 1111;
char a[maxn];
int ans[maxn];
int dmin[maxn][20];int minc(int i,int j)
{if(a[i]<=a[j])return i;return j;
}void initmin(int n)
{for(int i=0;i<n;i++)dmin[i][0] = i;for(int j=1;(1<<j)<=n;j++)for(int i=0;i+(1<<j)-1<n;i++)dmin[i][j] = minc(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
}int getmin(int l,int r)
{int k=0;while(1<<(k+1)<=r-l+1)k++;return minc(dmin[l][k],dmin[r-(1<<k)+1][k]);
}int main()
{int m;while(~scanf("%s%d",a,&m)){int n = strlen(a);int p = -1;initmin(n);for(int i=1;i<=n-m;i++){p=getmin(p+1,m+i-1);ans[i] = a[p] - '0';}int i;for(i=1;i<=n-m;i++)if(ans[i]!=0)break;if(i>n-m)puts("0");else{for(;i<=n-m;i++)printf("%d",ans[i]);cout<<endl;}}
}