每日一题 7.16 洛谷P1106

洛谷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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值