Codeforces 946E - Largest Beautiful Number(贪心、构造)


E. Largest Beautiful Number
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Yes, that’s another problem with definition of “beautiful” numbers.

Let’s call a positive integer x beautiful if its decimal representation without leading zeroes contains even number of digits, and there exists a permutation of this representation which is palindromic. For example, 4242 is a beautiful number, since it contains 4 digits, and there exists a palindromic permutation 2442.

Given a positive integer s, find the largest beautiful number which is less than s.

Input
The first line contains one integer t (1 ≤ t ≤ 105) — the number of testcases you have to solve.

Then t lines follow, each representing one testcase and containing one string which is the decimal representation of number s. It is guaranteed that this string has even length, contains no leading zeroes, and there exists at least one beautiful number less than s.

The sum of lengths of s over all testcases doesn’t exceed 2·105.

Output
For each testcase print one line containing the largest beautiful number which is less than s (it is guaranteed that the answer exists).

Example
inputCopy
4
89
88
1000
28923845
output
88
77
99
28923839


定义一个beautiful number就是长度为偶数,且数字重排后可以变成回文串,其实就是串内部所有的数字的出现次数都需要是偶数就对了。
现在给出一个字符串表示的数字s,让你找出比s小的最大的beautiful number。

为了让我们构造出来的结果尽量大而又不超过给定的s,当我们构造的串长度跟s相同时,就可以知道我们构造出来的串是前k-1位跟s对应位相同,第k位比s[k]小,然后后面k+1到n位能使串满足定义又尽量大。

所以我们从高位到低位枚举那个被修改小的位置k,然后从大到小枚举它被改成的数字,这样的复杂度是O(10*k),接下来如何判断成立与否了,因为前k-1位我们填的都是s串中对应的数,第k位又是我们枚举出来的,而我们又要满足所有数字出现次数为偶数次,所以前k位出现次数为奇数的数字都得在后面出现奇数次——所以,如果出现为奇数次的数字数量left大于n-k,则无法构造出来,否则可以。

至于构造方法,就是最后left位从大到小填上那些需要补全为偶数次的数字,中间剩余的位置都填9即可。

统计前k-1位每种数字出现的奇偶次数可以预处理出来,所以总复杂度是O(k)的。

若找不到满足的等长串,则输出n-2个9。

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=201015;
const int maxk=58500;
const int maxe=maxn*2;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
int n,m;
char str[maxn];
int cou[maxn][10];
void func(){
    for(int i=n;i>=1;i--){
        for(int j=str[i]-'0'-1;j>=0;j--){
            if(i==1&&j==0)continue;
            int lef=0;
            for(int k=0;k<10;k++){
                lef+=cou[i-1][k]^(j==k);
            }
            if(lef<=n-i){
                for(int k=1;k<i;k++){
                    putchar(str[k]);
                }
                putchar(j+'0');
                for(int k=i+1;k<=n-lef;k++)putchar('9');
                for(int k=9;k>=0;k--)if(cou[i-1][k]^(j==k))putchar(k+'0');
                putchar('\n');
                return;
            }
        }

    }
    for(int i=1;i<=n-2;i++)putchar('9');
    putchar('\n');
    return;
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",str+1);
        n=strlen(str+1);
        for(int i=1;i<=n;i++){
            int idx=str[i]-'0';
            for(int ii=0;ii<10;ii++)cou[i][ii]=cou[i-1][ii]^(ii==idx);
        }
        func();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值