笔/面试题题解

大概都是群友不会的东西,偶尔来支教一下

安装净化器(2021 ms 笔试题)

题⼲懒得复述了,题意我来概括下:给定⼀个字符串,由a、b、?三种字符组
成,要求给出⼀个⽤a和b替换所有?的⽅案,且结果中不存在⼤于等于3个连续
的a组合/b组合(结果不唯⼀)。

input output
a?bb aabb
b?a?bb bbaabb
??abb bbabb/ababb/baabb

我跟群友说这不就是最大子段和改编吗群友听不懂,然后就开了这个新专题,带领非竞赛选手(可能比较普通的竞赛选手也行?)见识一些过于常见的题目模型

经典模型:取或者不取问题(dp)+ dfs/循环 找dp方案

首先第一个经典模型,取或者不取问题。本题每位就是取a或者取b,所以和取不取问题是等价的,显然是可以去维护某一位作为末端的状态。

见过的都知道随便维护一个 \(dp_{i,(0/1)}\) 表示第 \(i\) 位取或者不取(a 还是 b)的最大值(最大连续段),当然这题其实也可以用一个状压之类的东西维护最后三位是什么字母,但是太麻烦了。

然后基本就写完了。

回溯部分也是个经典模型,是用 dp 解决问题之后求方案,那么这种情况有个问题就是空间复杂度一定是拉满的,也就是说不能进行滚动数组之类的骚操作,看不懂我也不知道怎么教了。

/*================================================================
*
*   创 建 者: badcw
*   创建日期: 2021/2/27 10:41 下午
*
================================================================*/
#include <bits/stdc++.h>

#define VI vector<int>
#define ll long long
using namespace std;

namespace IO {
    template<class T>
    void _R(T &x) { cin >> x; }
    void _R(int &x) { scanf("%d", &x); }
    void _R(ll &x) { scanf("%lld", &x); }
    void _R(double &x) { scanf("%lf", &x); }
    void _R(char &x) { x = getchar(); }
    void _R(char *x) { scanf("%s", x); }
    void R() {}
    template<class T, class... U>
    void R(T &head, U &... tail) {_R(head),R(tail...);}
    template<class T>
    void _W(const T &x) { cout << x; }
    void _W(const int &x) { printf("%d", x); }
    void _W(const ll &x) { printf("%lld", x); }
    void _W(const double &x) { printf("%.16f", x); }
    void _W(const char &x) { putchar(x); }
    void _W(const char *x) { printf("%s", x); }
    template<class T, class U>
    void _W(const pair<T, U> &x) {_W(x.first),putchar(' '),_W(x.second);}
    template<class T>
    void _W(const vector<T> &x) { for (auto i = x.begin(); i != x.end(); _W(*i++)) if (i != x.cbegin()) putchar(' '); }
    void W() {}
    template<class T, class... U>
    void W(const T &head, const U &... tail) {_W(head),putchar(sizeof...(tail) ? ' ' : '\n'),W(tail...);}
}
using namespace IO;


const int maxn = 5e5+50;
const int mod = 1e9+7;

ll qp(ll a, ll n) {
    ll res = 1;
    n %= mod - 1;
    if (n < 0) n += mod - 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

ll qp(ll a, ll n, int mod) {
    ll res = 1;
    n %= mod - 1;
    if (n < 0) n += mod - 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

string getans(string s) {
    string res = "";
    int n = s.length();
    vector<int> dp(n, -1), pd(n, -1);
    if (s[0] != 'b') dp[0] = 1;
    if (s[0] != 'a') pd[0] = 1;
    for (int i = 1; i < n; ++i) {
        if (s[i] != 'b') {
            if (dp[i - 1] != -1 && dp[i - 1] < 2) dp[i] = dp[i - 1] + 1;
            if (pd[i - 1] != -1) dp[i] = 1;
        }
        if (s[i] != 'a') {
            if (pd[i - 1] != -1 && pd[i - 1] < 2) pd[i] = pd[i - 1] + 1;
            if (dp[i - 1] != -1) pd[i] = 1;
        }
        // can't find a ans
        if (dp[i] == -1 && pd[i] == -1) return "";
    }

    // (loop / dfs) to find ans
    int p = 0;
    if (dp[n - 1] == -1) p = 1;
    for (int i = n - 1; i >= 0; --i) {
        res += "ab"[p];
        if (i == 0) break;
        if (p == 0 && dp[i] != dp[i - 1] + 1) p ^= 1;
        else if (p == 1 && pd[i] != pd[i - 1] + 1) p ^= 1;
    }
    reverse(res.begin(), res.end());
    return res;
}

int main(int argc, char* argv[]) {
    int T;
    scanf("%d", &T);
    for (int kase = 1; kase <= T; ++kase) {
        string s; R(s);
        W(getans(s));
    }
    return 0;
}
posted @ 2021-02-27 23:30  badcw  阅读(152)  评论(0编辑  收藏  举报