Codeforces Round #350 (Div. 2) F. Restore a Number

本文探讨了在数字传输过程中出现错误后的数字重构问题。面对一个被打乱的大数字和部分已知子串,目标是找出并还原原始的最小可能数字,同时避免前导零。文章详细解析了解决方案的思路,包括枚举数字位数、判断位数合法性及寻找最小数字的策略。

题意:

小明写了一个大数字 n ,然后再这个数字后面又加了一个数字 kkn 的位数
现在小明把完整的数字传给了小红, 但是在传输的过程中出现了意外,小红收到的数字的内容是打乱的, 现在知道的是小明还记得 大数字 n 的一部分,也就是他的字串,让你还原这个数字 n, 且让这个数字 n 尽可能的小。
记住,不能又前导零, 一个单个的 零 是允许的。

输入是小红收到的数
还有小明记住的数

思路:

有一点很容易想到, 这个 n 很大,也就是 n 的位数很多,但是 n 的位数这个数字的位数也就不超过8位, 所以我们就可以枚举 n 的位数这个数字的位数

  • 首先判断这个位数是不是合法
    • 如果合法
      • 判断能不能找到最小的数输出。

首先判断这个位数是不是合法,
我们枚举的位数 x 和 真正剩下的数lens - x的位数是不是一样的,
如果是一样的,再看看枚举的位数可不可以由剩下的数组成。

如果位数合法判断能不能组成最小的数。
现在问题转化成了
有一些数字, 还有一个有数字组成的字符串t, 怎样组合才可以让组成的数最小。

首先考虑能不能组成数, 也就是剩下的数是不是都是 0,
如果都是 0, 0 的个数有多少个,
如果 0 的个数大于1,那就GG, 如果就 1 个, 直接输出来。

  • 如果 t 的开头是 0, 单独输出来。 那么 t 就一定不是在总串的开头
  • 如果 t 的开头不是 0, 我们就弄出来两个字符串
    • t 在总串的开头
    • t 不在总串的开头,这种情况有可能不存在,注意考虑,因为 剩余的数字中有可能只有0或者不剩余数字。
  • 最终两个串比较一下就好了。

反思:

一开始就没有想到过用两个串进行比较的事,
一开始想的就是直接把这个最小的串构造出来。就导致要考虑的细节特别多。 这里少一个东西,那里少一个东西。

下次再遇到这样的题,
给你一些数字, 和一个字符串,构造一个最小的数字出来,
两步走,

  • 判断t串开头是不是 0,是 0 直接处理
  • 不是 0, 构造两个串出来,进行比较。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int n,m,lens,lent,a[10],b[10],c[10];
char s[N],t[N],l[N],r[N];
bool solve(int x){  //判断当前数字的位数是不是满足条件。位数最多是 1e6, 所以 k 最大就是7位。一个一个判断。
    for (int i = 0; i < 10; ++i)
        c[i] = a[i];
    if (lens - x <= 0){
        return false;
    }
    int tmp = lens - x,y,len = 0;
    while(tmp){
        y = tmp % 10;
        len++;
        c[y]--;
        if (c[y] < 0) return false;
        tmp /= 10;
    }
    if (len != x) return false;  //我假定的位数 和 真实的位数是不是一样的,如果不是那就false。
    return true;
}
void put0(){  // t 串开头是 0 的情况。 
    bool vis = 1;
    for (int i = 1; i < 10; ++i){
        if (c[i] && vis){
            printf("%d",i);
            vis = 0;
            for (int j = 1; j <= c[0]; ++j)
                printf("0");
            printf("%s",t+1);
            for (int j = 1; j < c[i]; ++j)
                printf("%d",i);
        } else
        for (int j = 1; j <= c[i]; ++j)
            printf("%d",i);
    }
    if (vis) printf("%s\n",t+1);//如果剩下的数字全在t串中,要单独考虑
    printf("\n");
    return;
}
bool put(int emmm){
    int x = t[1] - '0',y = 0; 
    for (int i = 1; i < 10; ++i)
        y += c[i];
    y += x;
    if (y == 0 && emmm > 1) return 0;   //判断是不是全零, 如果是一个零还是满足条件的,否则不满足条件。
    if (x == 0){
        put0();   // 首先判断 t 串的开头,不能是零, 不然是零的话不可以放在总串的开头。
        return 1;
    }
    y = 0;
    for (int i = 1; i <= lent; ++i)
        l[y++] = t[i];
    for (int i = 0; i < 10; ++i)
        for (int j = 1; j <= c[i]; ++j)
            l[y++] = i + '0'; 

    y = 0;
    for (int i = 1; i <= 9; ++i)
        if (c[i]){
            r[y++] = i + '0';
            c[i] --;
            break;
        }
    if (y == 0){   // 判断 去除了T 串, 剩下的数字不能当头, 如果不能就直接输出 t 串当头。 
        printf("%s\n",l);
        return 1;
    }
    x = t[1] - '0';
    for (int i = 2; i <= lent; ++i){
        if (t[i] > t[i-1]) break;
        if (t[i] < t[i-1]) {
            x--;
            break;
        }
    }
    for (int i = 0; i < 10; ++i){
        for (int j = 1; j <= c[i]; ++j)
            r[y++] = i + '0';
        if (i == x){
            for (int j = 1; j <= lent; ++j)
                r[y++] = t[j];
        }
    }
    if (strcmp(l,r) <= 0){  //两个串进行比较。 
        printf("%s\n",l);
    } else printf("%s\n",r);
    return 1;
}
int main(){
    scanf("%s",s+1);
    scanf("%s",t+1);
    lens = strlen(s+1);
    lent = strlen(t+1);
    for (int i = 1; i <= lens; ++i)
        a[s[i] - '0'] ++;
    for (int i = 1; i <= lent; ++i){
        a[t[i] -'0'] --;
        b[t[i] -'0'] ++;
    }
    for (int i = 7; i > 0; --i){
        if (solve(i)) {
            if (put(lens - i)) return 0;
        }
    }
    return 0;
}
【源码免费下载链接】:https://renmaiwang.cn/s/mgvj5 Ackley函数,作为优化算法测试领域的一个重要工具,它的设计初衷是为了评估和比较不同优化算法在处理复杂优化问题时的能力。这个函数具有多模态、非线性、非凸等特性,使得它成为检验全局搜索性能的理想选择。下面将详细探讨Ackley函数的定义、特点以及其在优化算法测试中的应用。Ackley函数由Dennis B. Ackley于1972年提出,其数学表达式如下:\[ f(x) = -20 \exp\left(-0.2\sqrt{\frac{1}{n}\sum_{i=1}^{n}x_i^2}\right) - \exp\left(\frac{1}{n}\sum_{i=1}^{n}\cos(2\pi x_i)\right) + 20 + e \]其中,\( n \) 是输入向量的维度,\( x_i \) 是输入向量的第\( i \)个元素,\( e \)是自然对数的底数(约等于2.718)。函数的目标是找到使该函数值最小化的\( x \)值。注意,此函数在全局最小值为0的位置处有多个局部极小值,这些极小值通常分布在整个定义域内,增加了求解的难度。 Ackley函数的主要特点如下:1. **多模态**:函数中包含了多个局部最小值,这模拟了实际问题中可能出现的复杂地形。2. **非线性**:函数的形状依赖于输入变量的平方和及余弦函数,这使得问题无法通过简单的线性操作解决。3. **非凸**:函数的等值线不是简单的圆形或椭圆形,而是呈现出复杂的曲面结构,进一步增加了优化的挑战。4. **全局最优解**:尽管存在多个局部最小值,但 Ackley 函数有一个全局最小值,即所有\( x_i = 0 \),函数值为0。在优化算法测试中,Ackley函数常被用来评估算法的全局搜索能力、收敛速度和稳定性。优化算法的目标是
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值