1. 程式人生 > 其它 >Codeforces1560E Polycarp and String Transformation(思維)

Codeforces1560E Polycarp and String Transformation(思維)

題目連結

題目大意

  給你一個初始字串s,你可以刪除字串s中的某個字元(比如刪除'a'就是把s中的所有'a'刪掉)得到一個字串t,把t拼接到s後面,再在t中刪除其他字元,繼續拼接到s後面直到t為空,給你最後拼接出的數字,讓你還原原來的數字並輸出字元的刪除順序。

解題思路

  感覺輸出字元的刪除順序算是個小提示?我的思路就是從刪除順序入手的。首先因為字元是一個一個刪除的,所以倒著遍歷一遍拼接出來的字串,每個字元第一次出現的順序正好是刪除順序的倒序。
  然後我們可以發現,假如字元的刪除序列長度為3,比如說"abacabaaacaac"這個樣例,刪除序列為"bac",那麼把原字串中每個字元的出現次數即為\(cnt[ch_i]\)

,那麼字元'c'就出現了\(cnt[c] \times 3\)次,字元'a'就出現了\(cnt[a] \times 2\)次,字元'b'就出現了"cnt[b] \times 1"次。
  觀察樣例還能發現一個性質:將每個t分成一段,後一段一定是前一段的子序列。
  我們倒著來遍歷拼接出來的字串,根據第一個性質,我們可以計算出每一組t包含的字元數量,於是我們能得到每組t位於哪個區間,然後我們還能得出在這組t中,每個字元應該出現的次數為多少,這個是判斷方案合法的根據之一,當然,只有數夠是不一定合法的,還得根據第二個性質,判斷前一個區間是否是當前區間的子序列。

const int maxn = 2e5+10;
const int maxm = 2e7+10;
int cnt[30], cnt2[maxn];
string s; 
bool judge(int l1, int r1, int l2, int r2) {
    int cnt = 0, len = r2-l2+1;
    for (int i = l1; i<=r1; ++i) {
        if (l2<=r2 && s[l2]==s[i]) ++l2, ++cnt;
    }
    return cnt == len;
}
int main() {
    IOS;
    int __; cin >> __;
    while(__--) {
        clr(cnt, 0);
        cin >> s;
        string od;
        for (int i = s.size()-1; i>=0; --i) {
            if (!cnt[s[i]-'a']) od += s[i];
            ++cnt[s[i]-'a'];
        }
        reverse(od.begin(), od.end());
        int p = od.size()-1, t = od.size();
        if (t==1) {
            cout << s << ' ' << od << endl;
            continue;
        }
        string ans; vector<P> tmp;
        bool ok = 1;
        if (cnt[od[p]-'a']%t) ok = 0;
        int sum = cnt[od[p]-'a']/t, res = sum, r = s.size()-1;
        for (int i = s.size()-1; i>=0 && ok; --i) {
            --res; ++cnt2[s[i]-'a'];
            if (res==0) {
                for (int i = p; i<od.size(); ++i) 
                    if (cnt2[od[i]-'a']!=cnt[od[i]-'a']/(i+1)) ok = 0;
                clr(cnt2, 0);
                tmp.push_back({i, r});
                r = i-1;
                if (ok && tmp.size()>1) {
                    auto it = tmp.rbegin();
                    int l1 = it->x, r1 = it->y;
                    ++it;
                    int l2 = it->x, r2 = it->y;
                    if (!judge(l1, r1, l2, r2)) ok = 0;
                } 
                --p, --t;
                if (t && cnt[od[p]-'a']%t) ok = 0;
                sum += cnt[od[p]-'a']/t;
                res = sum;
                if (p==0) {
                    if (sum!=i) ok = 0;
                    ans = s.substr(0, i);
                    break;
                }
            }
        }
        tmp.push_back({0, r});
        if (ok && tmp.size()>1) {
            auto it = tmp.rbegin();
            int l1 = it->x, r1 = it->y;
            ++it;
            int l2 = it->x, r2 = it->y;
            if (!judge(l1, r1, l2, r2)) ok = 0;
        } 
        if (ok) cout << ans << ' ' << od << endl;
        else cout << -1 << endl;
    }
    return 0;
}