Educational Codeforces Round 163 A-E

A. Special Characters

构造

形如 \(A\)\(B\) 这类单个字符构成的字符串对答案的贡献为 \(0\),而 \(AA\)\(AAAA\) 这类多个相同字符构成的字符串对答案的贡献固定为 \(2\)​,则无法构造出奇数值,由第二类字符串拼接即可构造出偶数值。

时间复杂度:\(O(n)\)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
    int n;
    cin >> n;

    if (n & 1) {
        cout << "NO\n";
    } else {
        cout << "YES\n";
        string ans;
        for (int i = 0; i < n / 2; i++) {
            ans.push_back('A' + i);
            ans.push_back('A' + i);
        }

        cout << ans << '\n';
    }
}

void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
}  

B. Array Fix

枚举/贪心

枚举:能执行操作的一定是两位数,且该操作一定会使被操作数分裂成两个个位数,则当我们对第 \(i\) 个数执行操作后,前 \(i - 1\)​ 个数中的两位数也得执行操作(因为两位数一定大于个位数),即执行操作的数一定为其前缀,所以枚举操作的前缀,再判断是否非递减即可。

贪心:当第 \(i\) 个数能分裂且分裂后不影响前 \(i\) 个数的非递减性质,则分裂更优(为后面的数分裂留出空间)。

时间复杂度:枚举 \(O(n^2)\),贪心 \(O(n)\)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
    int n;
    cin >> n;

    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }

    bool ans = false;
    for (int i = 0; i <= n; i++) {
        vector<int> b;
        for (int j = 1; j <= n; j++) {
            if (j <= i && a[j] >= 10) {
                b.push_back(a[j] / 10);
                b.push_back(a[j] % 10);
            } else {
                b.push_back(a[j]);
            }
        }
        int m  = b.size();
        bool f = true;
        for (int i = 1; i < m; i++) {
            if (b[i] < b[i - 1]) {
                f = false;
            }
        }
        if (f) {
            ans = true;
        }
    }

    if (ans) {
        cout << "YES\n";
    } else {
        cout << "NO\n";
    }
}

void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
} 

C. Arrow Path

搜索

按题中的行动方式进行 \(bfs\) 即可。

时间复杂度:\(O(n)\)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
    int n;
    cin >> n;

    vector<vector<char>> a(3, vector<char>(n + 1));
    for (int i = 1; i <= 2; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
        }
    }

    vector<vector<bool>> st(3, vector<bool>(n + 1));
    queue<array<int, 2>> q;
    q.push({1, 1});
    st[1][1] = true;
    vector<int> dx = {-1, 0, 0, 1}, dy = {0, 1, -1, 0};
    auto is_legal = [&](int x, int y)->bool {
        return 1 <= x && x <= 2 && 1 <= y && y <= n;
    };
    while (!q.empty()) {
        auto [x, y] = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if (is_legal(nx, ny)) {
                if (a[nx][ny] == '<') {
                    ny--;
                } else {
                    ny++;
                }
                if (!st[nx][ny]) {
                    st[nx][ny] = true;
                    q.push({nx, ny});
                }
            }
        }
    }

    if (st[2][n]) {
        cout << "YES\n";
    } else {
        cout << "NO\n";
    }
}

void prework() {

}

int main() {
    cctie;

    prework();

    int T;
    cin >> T;

    while (T--) {
        solve();
    }

    return 0;
}  

D. Tandem Repeats?

枚举/动态规划

枚举:考虑答案能否为 \(2k\),我们则要找一个子串 \(s[i...(i + k - 1)] = s[i+k...(i+2k-1)]\),构建一个新数组 \(b\)\(b[i]\) 表示 \(s[i]\) 是否等于 \(s[i + k]\),则要确定的是 \(b\) 数组中是否存在长度为 \(k\) 且和为 \(k\) 的子区间,这很容易 \(O(n)\) 解决,而 \(k\) 的取值为 \([0, {n\over2}]\),直接枚举即可。

动态规划:\(dpO(n^2)\) 预处理出所有后缀的最长公共前缀,然后 \(O(1)\) 判断每个子串是否能成为目标串。

时间复杂度:\(O(n^2)\)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
	string s;
	cin >> s;

	int n = s.size(), ans = 0;
	for (int l = 1; l <= n / 2; l++) {
		int cnt = 0;
		for (int i = 0, j = 0; i + l < n; i++) {
			if (s[i] == s[i + l] || s[i] == '?' || s[i + l] == '?') {
				cnt++;
				if (cnt == l) {
					ans = l * 2;
					break;
				}
			} else {
				cnt = 0;
			}
		}
	}

	cout << ans << '\n';
}
 
void prework() {

}

int main() {
	cctie;

	prework();

	int T;
	cin >> T;

	while (T--) {
		solve();
	}

	return 0;
}

E. Clique Partition

贪心、构造

考虑每一个团皆由连续的点集所构成,因为这样能使 \(|i - j|\) 最小,打表能发现点的数量小于等于 \(k\) 的团能构造,而 \(k + 1\) 的团不行,所以每 \(k\) 个点构成一个团,剩余不足 \(k\) 个的点构成一个团,构造方法为先使每个点的值为其编号即 \(a_i = i\),再在每个团的前、后半部分各自翻转。这样构造前、后半部分各自内部两点间的值显然不会超过 \(k\),而前后半部分各选一点间的值最多为 \(k\)

时间复杂度:\(O(n)\)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()

using i64 = long long;

void solve() {
	int n, k;
	cin >> n >> k;

	int col = 0;
	vector<int> a(n + 1), c(n + 1);
	iota(ALL(a), 1);
	for (int i = 1; i <= n; i += k) {
		int j = min(i + k - 1, n), h = i + j >> 1;
		reverse(a.begin() + i, a.begin() + h + 1);
		reverse(a.begin() + h + 1, a.begin() + j + 1);
		fill(c.begin() + i, c.begin() + j + 1, ++col);
	}

	for (int i = 1; i <= n; i++) {
		cout << a[i] << " \n"[i == n];
	}
	cout << col << '\n';
	for (int i = 1; i <= n; i++) {
		cout << c[i] << " \n"[i == n];
	}
}
 
void prework() {

}

int main() {
	cctie;

	prework();

	int T;
	cin >> T;

	while (T--) {
		solve();
	}

	return 0;
}
posted @ 2024-03-16 14:45  会有续命晴空  阅读(47)  评论(2编辑  收藏  举报