牛客周赛36

A 小红的数位删除

输出删除后三位数字的数

string n;cin >> n;
for (int i = 0;i < n.size() - 3;i++)cout << n[i];

B 小红的小红矩阵构造

检测是否满足所有元素之和恰好等于 x,且每行、每列的异或和全部相等

int a[110][110];
void solve() {
    int n, m, s;cin >> n >> m >> s;
    int sum = 0;
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            cin >> a[i][j];
            sum += a[i][j];
        }
    }
    if (sum != s) {
        cout << "wrong answer\n";return;
    }
    int x = a[1][1];
    for (int i = 2;i <= n;i++) {
        x ^= a[1][i];
    }
    for (int i = 1;i <= n;i++) {
        int r = a[i][1];
        for (int j = 2;j <= m;j++) {
            r ^= a[i][j];
        }
        if (r != x) {
            cout << "wrong answer\n";return;
        }
    }
    for (int i = 1;i <= n;i++) {
        int r = a[1][i];
        for (int j = 2;j <= m;j++) {
            r ^= a[j][i];
        }
        if (r != x) {
            cout << "wrong answer\n";return;
        }
    }
    cout << "accepted\n";
}

C 小红的白色字符串

小红拿到了一个字符串,她准备将一些字母变成白色,变成白色的字母看上去就和空格一样,这样字符串就变成了一些单词。
现在小红希望,每个单词都满足以下两种情况中的一种:

  1. 开头第一个大写,其余为小写(长度为 1 的大写字母也是合法的)。
  2. 所有字符全部是小写。

小红想知道,最少需要将多少字母变成白色?

void solve() {
    string s;cin >> s;
    s = ' ' + s;
    int ans = 0, cnt = 0;
    for (int i = 1;i < s.size();i++) {
        cnt = 0;int ok = 0;
        while (isupper(s[i])) {
            if (i == 1) {
                ok = 1;
            }
            cnt++;i++;
        }
        ans += (cnt - ok + 1) / 2;
    }
    cout << ans << '\n';
}

D 小红走矩阵

小红来到了一个n∗m 的矩阵,她初始站在左上角,每次行走可以按“上下左右”中的一个方向走一步,但必须走到和当前格子不同的字符,也不能走到矩阵外。

小红想知道,从左上角走到右下角最少需要走多少步?

BFS 板子

#define pll pair<int,int> 
char g[1010][1010];
int n, m;
int vis[1010][1010], dis[1010][1010];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
int bfs(int x, int y) {
    queue<pll> q;
    vis[x][y] = 1;
    q.push({x,y});
    dis[x][y] = 0;
    while (q.size()) {
        auto t = q.front();q.pop();
        for (int i = 0;i < 4;i++) {
            int a = t.first + dx[i];
            int b = t.second + dy[i];
            if (a<1 || a>n || b<1 || b>m)continue;
            if (vis[a][b])continue;
            if (g[a][b] == g[t.first][t.second])continue;
            vis[a][b] = 1;
            dis[a][b] = dis[t.first][t.second] + 1;
            q.push({a,b});
        }
    }
    if (!dis[n][m])dis[n][m] = -1;
    return dis[n][m];
}
void solve() {
    cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            cin >> g[i][j];
        }
    }
    cout << bfs(1, 1) << "\n";
}

E 小红的小红走矩阵

造 D 的数据,要求:

  1. 直接输出 n + m - 2 会返回答案错误,换句话说,“小红走矩阵”这题的正确代码运行后的结果不是 n + m - 2。
  2. 直接输出 n * m - 1 也会返回答案错误,换句话说,“小红走矩阵”这题的正确代码运行后的结果不是 n * m - 1。
  3. 生成的矩阵中,不存在“绝对众数”。(即,没有任何字符的出现次数大于 n * m / 2 向上取整)
  4. 生成的矩阵必须能从 (1,1) 走到 (n, m),换句话说,“小红走矩阵”这题的正确代码运行后的结果不是 -1。

Solution

构造

我赛时的想法:(当 n 和 m 比较小的时候就不可行)

int n, m;
char a[1010][1010];
void solve() {
    cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            a[i][j] = 'A';
        }
    }
    for (int i = 1;i <= m;i++) {
        if (i % 2)a[1][i] = 'a';
        else a[1][i] = 'b';
    }
    for (int i = 2;i <= n;i++) {
        if (i % 2 == 0)a[i][m] = (a[1][m] == 'a' ? 'b' : 'a');
        else a[i][m] = (a[1][m] == 'a' ? 'a' : 'b');
    }
    a[n - 1][m] = a[n][m];
    a[n - 2][m - 1] = (a[n - 1][m] == 'a' ? 'b' : 'a');
    a[n - 1][m - 1] = (a[n - 2][m - 1] == 'a' ? 'b' : 'a');
    a[n][m - 1] = (a[n - 1][m - 1] == 'a' ? 'b' : 'a');
    for (int i = 2;i <= n;i++) {
        for (int j = 1;j < m;j++) {
            if (isupper(a[i][j])) {
                if (i % 4 == 2 || i % 4 == 3)
                    a[i][j] = 'c';
                else a[i][j] = 'd';
            }
        }
    }
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            cout << a[i][j];
        }cout << '\n';
    }
}

其实按照样例来构造就可以了...

将样例给出的 9 个字符放进去之后,后面随意构造即可。

char a[1010][1010];
void solve() {
    int n, m;cin >> n >> m;
    a[1][1] = 'a';a[1][2] = 'b';a[1][3] = 'b';
    a[2][1] = 'a';a[2][2] = 'c';a[2][3] = 'c';
    a[3][1] = 'b';a[3][2] = 'c';a[3][3] = 'b';
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            if (!islower(a[i][j])) {
                a[i][j] = 'A';
            }
        }
    }
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            if (isupper(a[i][j])) {
                a[i][j] = 'a' + (i + j) % 26;
            }
        }
    }
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            cout << a[i][j];
        }cout << '\n';
    }
}

F 小红的好子串询问

小红定义一个字符串是“好串”,当且仅当该字符串不包含长度不小于 2 的回文子串。
现在小红拿到了一个仅包含"red"三种字符的字符串,她有如下两个操作:

Solution

树状数组/线段树

看不懂...坐等视频()
待补:小白月赛 88,ARC

要满足这题的要求,只能是 "red","rde","dre","der","erd","edr" 六种字符串循环才能保证不会出现长度不小于 2 的回文子串。

就枚举六种情况,看哪一种使用的次数最少即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

#define N 100000

int i, j, k, n, m, t;

string s, s1, _s[7] = {"","red","rde","dre","der","erd","edr"};

int f[7][N + 50];

void add(int f[], int x, int y) { for (;x <= n;x += (-x & x)) { f[x] += y; } }
int get(int f[], int x, int y = 0) { for (;x;x -= (-x & x)) { y += f[x]; }return y; }

int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n >> t >> s; s = "$" + s;
    for (i = 1;i <= n;i++) {
        for (j = 1;j <= 6;j++) {
            add(f[j], i, s[i] != _s[j][i % 3]);
        }
    }
    while (t--) {
        int l, r, res, op;
        cin >> op;
        if (op == 1) {
            cin >> l >> s1;
            for (j = 1;j <= 6;j++) {
                add(f[j], l, -(s[l] != _s[j][l % 3]));
            }
            s[l] = s1[0];
            for (j = 1;j <= 6;j++) {
                add(f[j], l, (s[l] != _s[j][l % 3]));
            }
        } else {
            cin >> l >> r;
            res = 1e9;
            for (i = 1;i <= 6;i++) {
                res = min(res, get(f[i], r) - get(f[i], l - 1));
            }
            cout << res << '\n';
        }
    }
}