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;
}
發佈了237 篇原創文章 · 獲贊 13 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章