Educational Codeforces Round 39 (Rated for Div. 2) E Largest Beautiful Number

29 篇文章 0 订阅
10 篇文章 0 订阅

题目链接:点击打开链接

题意:定义一种数,这里不妨称之为BN:它的十进制表示只有偶数位数,且不含前导零;此外,它的十进制表示的每个位上的数经过重新排列后能形成回文序列。在这里给定某个数n(十进制下长度不超过2*1e5),求小于它的最大BN。(题目数据保证有解且n不含前导零)

思路:贪心。首先,n的长度可能很大,这里需要使用字符串来处理该数。

因为要找一个比n小的BN数,假设该数的前i位数已经确定,那么第i+1位数的确定即判断是否存在一个满足条件的后缀,而要形成回文序列的性质使得这个后缀数非常好找。寻找的过程即根据已经确定的数,找到出现次数为奇数的所有数,从小到大排到后缀的最后即可,中间部分(贪心地)用0补充。

这里因为前缀必然是满足条件的,所以随着i的增大,寻找后缀的方法不变:即判断第i+1位数是否存在一个满足条件的后缀,如果满足那么就判断下一位直到最后,否则令现有的i+1位前缀减1,继续执行上述判断。 所以这样的方式并不具有后效性。故令i从1到len(n)走一遍即可,若直到出现前导零时都找不到解,那么需要将位数减小,新位数下所有数必然小于n,故全为9。

AC代码如下:

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;

const int MAXN = 2000005;
int cnt[10];
string ss;
string tt;

int flag;
vector<int> comp;

int check(int pos)
{
    comp.clear();
    int allzero = 1;
    tt[pos-1] = ss[pos-1];
    cnt[ss[pos-1]-'0']++;
    for(int i=0; i<10; ++i)
    {
        if(cnt[i]%2)
            comp.push_back(i);
        if(cnt[i]&&i)  allzero=0;
    }
    if(allzero) return 0;

    sort(comp.begin(),comp.end());
    int len = comp.size();
    if(len==0)  return 1;
    if(comp.size()<ss.length()-pos) return 1;
    if(comp.size()>ss.length()-pos) return 0;
    for(int i=1; i<=len; ++i)
        tt[ss.length()-i] = '0'+comp[len-i];

     /*
    string ttmp = ss;
    string ssmp = tt;*/
    for(int i=pos; i<ss.length(); ++i)
    {
        if(tt[i]<ss[i]) return 1;
        else  if(tt[i]>ss[i])   return 0;
    }
    return 1;
}

int reduce(int pos)
{
    for(int i=pos+1; i<ss.length(); ++i)  ss[i]='9',tt[i]='0';
    int tmp = pos;
    while(tmp>=0&&ss[tmp]=='0')
    {
        ss[tmp]='9';
        tt[tmp]='0';
        cnt[0]--;
        tmp--;
    }
    if(tmp<0)   return -1;
    cnt[ss[tmp]-'0']--;
    ss[tmp]--;
    if(ss[0]=='0')  return -1;
    return tmp;
}

void solve()
{
    memset(cnt,0,sizeof(cnt));
    for(int j=0; j<ss.length(); ++j)  cnt[ss[j]-'0']++;
    int isbeautiful = 1;
    for(int j=0; j<10; ++j)
    {
        if(cnt[j]%2)
        {
            isbeautiful=0;
            break;
        }
    }
    if(isbeautiful) reduce(ss.length()-1);

    memset(cnt,0,sizeof(cnt));
    tt = string(ss.length(),'0');

    for(int i=0; i<ss.length(); ++i)
    {
        if(!check(i+1))
        {
            int retmp = reduce(i);
            if(retmp==-1)
            {
                for(int j=1; j<=ss.length()-2; ++j)
                    cout<<'9';
                cout<<endl;
                return;
            }

            i = retmp - 1;
            //cout<<ss<<endl;
        }
    }
    cout<<tt<<endl;
}

int main()
{
    FSIO;
    int T;
    cin>>T;
    while(T--)
    {
        flag = 0;
        cin>>ss;
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值