F2. Nearest Beautiful Number (hard version) (思維+分類討論+枚舉)


差點AKdiv3www

 

 首先這道題肯定不能暴力了啦。之后我們發現這道題其實跟數位dp非常的相像。那么數位dp的時候,一旦某一位變大了,那么后面的數字其實是隨便選的,因為不管怎么選,這個數字肯定是大於之前的數的。

比如122245與123***肯定不管怎么取*的數字肯定是比122245大的。

之后這道題又要取最小,我們可以想到從最后開始枚舉,因為修改的數位越小,那么肯定是越小的。

所以就能想到暴力枚舉每一位,如果出現了合法的答案就肯定是這個了。

那么如果是兩個for進行枚舉(枚舉當前修改的數字,以及后面的所有要變成的數字)是會T的,T了3發。

所以我們考慮優化這個過程。

如果當前數位改變了,如果算上當前這位數,不同的數字是< k的,那么我們就將后面的所有數字變成0。

如果 == k 那么我們就需要從前面的k個數里選最小的數進行填充。

之后判斷是否合法就好了。

 

用string和set寫的常數好像有點大。

#include <bits/stdc++.h>
using namespace std;
string n;
int k;

int cal(string ss) {
    set<char> s;
    for (auto c : ss) s.insert(c);
    return s.size();
}

string solve() {
    cin >> n >> k;
    if (cal(n) <= k) return n;
    int len = n.size();
    for (int i = len-1; i >= 0; i --) {
        string temp = n;
        ///如果當前位提高了1,那么后面的數只有取0或者取之前最小的情況
        for (char j = n[i]+1; j <= '9'; ++ j) {
            set<char> ck;
            for (int l = 0; l < i; ++ l) ck.insert(n[l]);
            temp[i] = j;
            ck.insert(j);
            if (cal(temp.substr(0, i+1)) > k) continue;

            char p = cal(temp.substr(0, i+1)) < k ? '0' : *ck.begin();
            for (int l = i+1; l < len; ++ l) temp[l] = p;
            if (stoi(temp) >= stoi(n))
                return temp;
        }

    }
    return "";
}

int main() {
    int t; cin >> t;
    while (t--)
        cout << solve() << '\n';
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM