洛谷P1106删数问题
题
题目描述
键盘输入一个高精度的正整数 N(不超过 250 位),去掉其中任意 k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N和 k,寻找一种方案使得剩下的数字组成的新数最小。
输入格式
n(高精度的正整数 )。
k(需要删除的数字个数 )。
输出格式
最后剩下的最小数。
解
解一 贪心删数
贪心出来的一个结论。
递减删,也就是s[i]>s[i+1]就删去s[i]。因为在还有k剩余的情况下,删去高位且大的数肯定比删去低位的数要优。如果不存在,说明是不降序列,那么显然删去最后一个是最优的。
注意前导零。
如果能全部删完就特判0 。
code
int main()
{
//char s[266];
string s;
cin>>s;
int k;cin>>k;
//int n=strlen(s);
int n=s.length();
if(k>=n){cout<<0<<'\n';return 0;}
while(k--){
//bool flag=0;
for(int i=0;i<n-1;i++){
if(s[i]>s[i+1]){
//for(int k=i;k<n-1;k++)s[k]=s[k+1];
//flag=1;
s.erase(i,1);
break;
}
}
n--;//长度减少的同时能实现不降删末尾
}
int p=0;while(p<n&&s[p]=='0')p++;//前导零
if(p==n){cout<<0<<'\n';return 0;}//只剩零
for(int i=p;i<n;i++)cout<<s[i];cout<<'\n';
//system("pause");
return 0;
}
解二 逆向填数
删数反过来想我们可以当成填充数。
假设长n,删k,那么结果长n-k。我们需要找出n-k个数来填充组成答案。
显然我们应该高位往低位填充,想要答案合法,就要满足每次填入的数应该是剩下数里最小的,并且其位置要在填充的是上一个数的位置后方。
再进一步想,最多填充n-k个数,那么可以枚举一个长为k+1的区间,这样子剩下的有n-k-1个,那么必定需要从这个区间里选出至少一个出来,选的原则是选最小的,之后再把区间往右移动一位。
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct Node{
int m;int pos;
}s[266];
string n;
int k;
bool has[266];
bool cmp(Node a,Node b){
if(a.m==b.m)return a.pos<b.pos;
else return a.m<b.m;
}
int main()
{
cin>>n>>k;
int len=n.length();
for(int i=0;i<len;i++){
s[i].m=n[i]-'0';s[i].pos=i;
}
sort(s,s+len,cmp);
int p=len-k;
int ans[266];
int all=0;
int last=-1;
while(p){
for(int i=0;i<len;i++){
if(!has[i]&&s[i].pos>last&&s[i].pos<len-p+1){
last=s[i].pos;
ans[all++]=s[i].m;
has[i]=1;
p--;
break;
}
}
}
int flag=0;
for(int i=0;i<all;i++){
if(ans[i]!=0||flag){
flag=1;cout<<ans[i];
}
}
if(flag==0)cout<<0;
cout<<'\n';
//system("pause");
return 0;
}