• Google kickstart 2022 Round A题解


    Speed Typing#

    题意概述#

    给出两个字符串IP,问能否通过删除P中若干个字符得到I?如果能的话,需要删除字符的个数是多少?

    数据规模#

    1|I|,|P|105
    1|I|,|P|105

    双指针#

    设置两个指针ij分别指向IP的第一个字符,滑动指针j,如果j指向的字符与i指向的字符相同,则让i向后滑动一个字符,当i滑动到I字符串末尾或j滑动到P字符串末尾后即可结束循环。如果i滑动到I字符串末尾,则说明可以通过删除P中若干个字符得到I,那么删除的字符个数为|P||I||P||I|;反之则不能。

    复杂度#

    • 时间复杂度为O(max(|I|,|P|))O(max(|I|,|P|))
    • 空间复杂度为O(1)O(1)

    C++代码#

    #include <bits/stdc++.h>
    using namespace std;
    using gg = long long;
    #define rep(i, a, b, c) for (gg i = (a); i <= (b); i += (c))
    #define rrep(i, a, b, c) for (gg i = (a); i >= (b); i -= (c))
    constexpr gg MAX = 1e6 + 5;
    constexpr gg mod = 1e9 + 7;
    constexpr gg INF = 4e18;
    constexpr double eps = 1e-12;
    gg ti, ni, mi, ki, di, pi, xi, yi;
    gg up(gg n, gg m) { return n >= 0 ? (n + m - 1) / m : n / m; }
    gg down(gg n, gg m) { return n >= 0 ? n / m : (n - m + 1) / m; }
    //! ti; MAX; mod; 边界
    void solve() {
        string s1, s2;
        cin >> s1 >> s2;
        gg i = 0, j = 0;
        for (; i < s1.size() and j < s2.size(); ++i, ++j) {
            while (j < s2.size() and s1[i] != s2[j]) {
                ++j;
            }
            if (j == s2.size()) {
                break;
            }
        }
        i == s1.size() ? cout << s2.size() - s1.size() : cout << "IMPOSSIBLE";
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        ti = 1;
        cin >> ti;
        for (gg ii = 1; ii <= ti; ++ii) {
            cout << "Case #" << ii << ": ";
            solve();
            cout << "\n";
        }
        return 0;
    }
    

    Challenge Nine#

    题意概述#

    给定一个正整数NN,在给定的数字NN的任意位置插入一个[0,9]之间的数字,得到一个不带前导零的新的数字,需要保证这个新的数字是9的倍数。问能构造出的最小的数字是多少?

    数据规模#

    1N10123456
    1N10123456

    贪心#

    由于给出的数字非常大,需要用字符串读入。易知一个数字是9的倍数的充要条件是该数各位上的数字之和也是9的倍数。因此,先计算出读取的字符串各位上的数字之和sum,遍历0~9这10个数字,假设当前遍历到的数字是i,如果isum之和是9的倍数,说明插入i能够保证新数字是9的倍数。接着从N的高位向低位遍历,假设当前遍历到的位上的数字是j,如果i<j,则将i插入到j之前可以得到最小的数字(想一想为什么?)。

    复杂度#

    • 时间复杂度为O(n)O(n)
    • 空间复杂度为O(n)O(n)

    其中nn指的是数字N的位数。

    C++代码#

    #include <bits/stdc++.h>
    using namespace std;
    using gg = long long;
    #define rep(i, a, b, c) for (gg i = (a); i <= (b); i += (c))
    #define rrep(i, a, b, c) for (gg i = (a); i >= (b); i -= (c))
    constexpr gg MAX = 1e6 + 5;
    constexpr gg mod = 1e9 + 7;
    constexpr gg INF = 4e18;
    constexpr double eps = 1e-12;
    gg ti, ni, mi, ki, di, pi, xi, yi;
    gg up(gg n, gg m) { return n >= 0 ? (n + m - 1) / m : n / m; }
    gg down(gg n, gg m) { return n >= 0 ? n / m : (n - m + 1) / m; }
    //! ti; MAX; mod; 边界
    void solve() {
        string n;
        cin >> n;
        gg m = n.size(), sum = 0;
        array<gg, 2> ans{m + 1, 10};
        for (char c : n) {
            sum += c - '0';
        }
        n.push_back(10 + '0');
        rep(i, 0, 9, 1) {
            if ((i + sum) % 9 == 0) {
                rep(j, 0, m, 1) {
                    if (n[j] - '0' > i and (j > 0 or i != 0) and ans[0] > j) {
                        ans = {j, i};
                        break;
                    }
                }
            }
        }
        n.pop_back();
        cout << n.substr(0, ans[0]) << ans[1] << n.substr(ans[0]);
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        ti = 1;
        cin >> ti;
        for (gg ii = 1; ii <= ti; ++ii) {
            cout << "Case #" << ii << ": ";
            solve();
            cout << "\n";
        }
        return 0;
    }
    

    Palindrome Free Strings#

    题意概述#

    给出一个长度为NN的只包含01?构成的字符串S,可以随机用01替换掉字符串S中所有的?,问能否找到一种替换方法,使得所得到的串没有长度大于等于5的回文子串。

    数据规模#

    1<=N<=5×104
    1<=N<=5×104

    动态规划#

    首先需要注意到,如果字符串S中包含长度为n(n>2)n(n>2)的回文子串,那么将该回文子串首尾两个字符,那么得到的长度为n2的子串必然也是回文的,因此,可以得到结论:如果S中不包含长度为5的回文子串,那么S中必然也不包含长度为5+2k(k>0)的回文子串;如果S中不包含长度为6的回文子串,那么S中必然也不包含长度为6+2k(k>0)的回文子串。因此,只要能够找到一种替换方法使得S不包含长度为5和6的回文子串,那么S中必然也没有长度大于等于5的回文子串。

    一种暴力的方法,是通过递归的方法将S中的字符?逐个替换为01,并验证得到的字符串中是否存在长度为5或6的回文子串,时间复杂度为O(n2n),这种方法能够通过小数据。下面主要介绍通过大数据的方法。

    显然,暴力方法的时间复杂度为指数级,可以通过动态规划将时间复杂度降低到多项式级别。先进行分类讨论:如果S长度小于5,那么该字符串无论怎么替换?字符,都可以满足要求,直接输出POSSIBLE即可;如果S长度为5,那么可以暴力枚举所有可能得到的替换后的字符串,并验证该字符串是否为回文串即可;下面主要讨论S长度大于5的情况。

    dp[i]表示以S的前i个字符能否找到一种替换方法保证没有长度大于等于5的回文子串。由于要验证是否包含长度为6的回文子串,那么在每次添加新的字符S[i]时,S[i]能否构成长度为6的回文子串与S[i]前面的5个字符S[i-5],S[i-4],S[i-3],S[i-2],S[i-1]有关,因此,可以为S[i]的前5个字符标记一个状态,由于每个字符的取值只有01两种,因此状态总数为25。针对字符S[i],暴力枚举以S[i]结尾的长度为6的子串的可能替换结果字符串j,如果j包含长度为5或6的回文子串,则不符合题目要求;否则dp[i][j]=dp[i1][j],其中j=S[i6]+j[:5]。具体实现可参考代码。

    复杂度#

    • 时间复杂度为O(2KN)
    • 空间复杂度为O(2KN)

    其中K=5

    C++代码#

    #include <bits/stdc++.h>
    using namespace std;
    using gg = long long;
    #define rep(i, a, b, c) for (gg i = (a); i <= (b); i += (c))
    #define rrep(i, a, b, c) for (gg i = (a); i >= (b); i -= (c))
    constexpr gg MAX = 1e5 + 5;
    constexpr gg MAX2 = 70;
    constexpr gg mod = 1e9 + 7;
    constexpr gg INF = 4e18;
    constexpr double eps = 1e-12;
    gg ti, ni, mi, ki, di, pi, xi, yi;
    gg up(gg n, gg m) { return n >= 0 ? (n + m - 1) / m : n / m; }
    gg down(gg n, gg m) { return n >= 0 ? n / m : (n - m + 1) / m; }
    //! ti; MAX; mod; 边界
    bool dp[MAX][MAX2];
    string s;
    void dfs(gg p, gg r, string cur, vector<string>& v) {
        if (p > r) {
            v.push_back(cur);
            return;
        }
        if (s[p] != '1') {
            dfs(p + 1, r, cur + "0", v);
        }
        if (s[p] != '0') {
            dfs(p + 1, r, cur + "1", v);
        }
    }
    bool isPalic(const string& s) { return equal(s.begin(), s.end(), s.rbegin()); }
    void solve() {
        cin >> ni >> s;
        if (ni <= 4) {
            cout << "POSSIBLE";
        } else if (ni == 5) {
            vector<string> v;
            dfs(0, 4, "", v);
            bool ans = all_of(v.begin(), v.end(), isPalic);
            cout << (ans ? "IMPOSSIBLE" : "POSSIBLE");
        } else {
            bool ans = false;
            rep(i, 5, ni - 1, 1) {
                vector<string> v;
                dfs(i - 5, i, "", v);
                for (string& k : v) {
                    gg cur = stoll(k, 0, 2);
                    dp[i][cur] = not(isPalic(k) or isPalic(k.substr(0, 5)) or isPalic(k.substr(1, 5)));
                    if (i >= 6) {
                        bool res = false;
                        if (s[i - 6] != '1') {
                            res = res or dp[i - 1][stoll("0" + k.substr(0, 5), 0, 2)];
                        }
                        if (s[i - 6] != '0') {
                            res = res or dp[i - 1][stoll("1" + k.substr(0, 5), 0, 2)];
                        }
                        dp[i][cur] = dp[i][cur] and res;
                    }
                    if (i == ni - 1) {
                        ans = ans or dp[i][cur];
                    }
                }
            }
            cout << (ans ? "POSSIBLE" : "IMPOSSIBLE");
        }
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        ti = 1;
        cin >> ti;
        for (gg ii = 1; ii <= ti; ++ii) {
            cout << "Case #" << ii << ": ";
            solve();
            cout << "\n";
        }
        return 0;
    }
    

    Interesting Integers#

    题意概述#

    如果一个整数的所有数字的乘积能被所有数字的和整除,就称这个整数为有趣的。给出两个整数AB,找出[A,B]之间有趣的整数个数。

    数据规模#

    1AB105

    算法设计#

    目前只会解小数据,大数据的解法可参考Google Kick Start 2022 Round A 题解。通过枚举[A,B]之间的数字,暴力判断组成该整数的所有数字的乘积能能否被所有数字的和整除即可。

    复杂度#

    • 时间复杂度为O(n)
    • 空间复杂度为O(n)

    其中n=BA+1

    C++代码#

    #include <bits/stdc++.h>
    using namespace std;
    using gg = long long;
    #define rep(i, a, b, c) for (gg i = (a); i <= (b); i += (c))
    #define rrep(i, a, b, c) for (gg i = (a); i >= (b); i -= (c))
    constexpr gg MAX = 1e5 + 5;
    constexpr gg MAX2 = 70;
    constexpr gg mod = 1e9 + 7;
    constexpr gg INF = 4e18;
    constexpr double eps = 1e-12;
    gg ti, ni, mi, ki, di, pi, xi, yi;
    gg up(gg n, gg m) { return n >= 0 ? (n + m - 1) / m : n / m; }
    gg down(gg n, gg m) { return n >= 0 ? n / m : (n - m + 1) / m; }
    //! ti; MAX; mod; 边界
    bool func(gg n) {
        gg s = 0, p = 1;
        while (n > 0) {
            s += n % 10;
            p *= n % 10;
            n /= 10;
        }
        return p % s == 0;
    }
    void solve() {
        cin >> xi >> yi;
        gg ans = 0;
        rep(i, xi, yi, 1) {
            if (func(i)) {
                ++ans;
            }
        }
        cout << ans;
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        ti = 1;
        cin >> ti;
        for (gg ii = 1; ii <= ti; ++ii) {
            cout << "Case #" << ii << ": ";
            solve();
            cout << "\n";
        }
        return 0;
    }
    
  • 相关阅读:
    【愚公系列】2022年09月 微信小程序-WebGL纹理材质的使用
    Seata设计核心原理
    收单外包机构为何会被强制取消备案
    追求极致性能,RocketMQ 消息通信详解
    Spring面试攻略:如何展现你对Spring的深入理解
    在通用jar包中引入其他spring boot starter,并在通用jar包中直接配置这些starter的yml相关属性
    Sim3相似变换
    kubectl 声明式资源管理方式
    思考(八十八):使用 protobuff 自定义选项,做数据多版本管理
    Docker网络模式之bridge-尚文网络xUP楠哥
  • 原文地址:https://www.cnblogs.com/richenyunqi/p/16154238.html