作为一名参加过多次CCPC区域赛的选手,这次郑州站的题目给我留下了深刻印象。题目整体难度适中,既有考察基础能力的签到题,也有需要深入思考的中等难度题。下面我将对部分题目进行详细解析,希望能帮助备赛的同学们更好地理解解题思路。
这道题要求我们判断一个数字是否满足两个条件:
判断完全平方数的常见方法是计算平方根后取整,再将结果平方看是否等于原数。这样可以避免浮点数精度问题。
关键点在于:
cpp复制#include<bits/stdc++.h>
using namespace std;
bool is_square(int x){
int sq1 = sqrt(x);
return sq1 * sq1 == x;
}
bool check(int x){
if(!is_square(x)) return false;
int res = 0;
while(x){
res += (x % 10);
x /= 10;
}
return is_square(res);
}
int main(){
int y; cin >> y;
cout << (check(y) ? "Yes" : "No");
return 0;
}
给定一个字符串,我们可以将每个字母循环后移k位(k∈[0,25]),要求找到使新字符串权值最大的k值。权值规则是每个字母对应一个固定权值。
cpp复制#include<iostream>
#include<vector>
using namespace std;
vector<int> holes_cnt = {1,2,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0};
int main() {
string s; cin >> s;
int final_ans = 0;
for(int i = 0; i <= 25; i++) {
int ans = 0;
for(auto& c : s) {
ans += holes_cnt[(c - 'A' + i) % 26];
}
final_ans = max(ans, final_ans);
}
cout << final_ans;
return 0;
}
定义f(n)=n·(n+1),如果存在f(n)=f(a)·f(b),则n与a、b相连。问从节点s出发,区间[l,r]内有多少可达节点。
通过枚举小规模的n值可以发现:
cpp复制#include<bits/stdc++.h>
using namespace std;
int main(){
int t; cin >> t;
while(t--){
int s, l, r; cin >> s >> l >> r;
cout << r - l + 1 << '\n';
}
return 0;
}
给定n个节点和m条边,通过增加或删除边,使得最终形成一棵树(连通无环)。求最小操作次数。
使用并查集数据结构:
cpp复制class UnionFind{
public:
vector<int> father;
int sets;
UnionFind(int n) : father(n+1) {
for(int i=0; i<n; i++) father[i] = i;
sets = n;
}
int find(int i) {
if(i != father[i]) {
father[i] = find(father[i]);
}
return father[i];
}
bool isSameSet(int x, int y) {
return find(x) == find(y);
}
void Union(int x, int y) {
int fx = find(x);
int fy = find(y);
if(fx != fy) {
father[fx] = fy;
sets--;
}
}
};
cpp复制int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m; cin >> n >> m;
UnionFind uf(n);
int ans = 0;
for(int i=1; i<=m; i++){
int x, y; cin >> x >> y;
if(uf.isSameSet(x, y)){
ans++;
} else {
uf.Union(x, y);
}
}
ans += (uf.sets - 1);
cout << ans;
return 0;
}
构造一个满足特定条件的图,当n=4时无解,其他情况需要分奇偶讨论。
cpp复制void get_ans(int x) {
for(int i=2; i<=x-1; i+=2) {
if(i == 2) {
cout << "1 2\n";
} else {
cout << i-2 << " " << i << '\n';
}
cout << i << " " << i+1 << '\n';
}
}
int main() {
int t; cin >> t;
while(t--) {
int x; cin >> x;
if(x == 4) cout << -1 << '\n';
else if(x % 2) get_ans(x);
else {
get_ans(x-1);
cout << x-1 << " " << x << '\n';
}
}
return 0;
}
经典迷宫问题变种,允许在遇到障碍时使用一次药剂,使得后续k步可以穿越障碍。求到达终点的最小k值。
使用多源BFS:
cpp复制vector<pair<int,int>> dir = {{-1,0},{1,0},{0,1},{0,-1}};
int main() {
int t; cin >> t;
while(t--) {
int n, m; cin >> n >> m;
auto graph = vector(n, vector<char>(m));
// 输入处理
// 起点可达区域
auto st = vector(n, vector<bool>(m, false));
queue<pair<int,int>> que;
que.push({0,0});
st[0][0] = true;
// BFS过程...
// 终点可达区域
auto end = vector(n, vector<bool>(m, false));
que.push({n-1,m-1});
end[n-1][m-1] = true;
// BFS过程...
// 多源BFS
auto used = vector(n, vector<bool>(m, false));
auto distance = vector(n, vector<int>(m, INT_MAX));
// 初始化队列...
int ans = 0;
while(!que.empty()) {
auto [x,y] = que.front(); que.pop();
if(end[x][y]) {
ans = distance[x][y];
break;
}
// 扩展节点...
}
cout << (ans == 0 ? ans : ans-1) << '\n';
}
return 0;
}
给定2n个字符串,分成两组(引和根),每组n个。计算所有引和根字符串对的最长公共前缀之和,要求这个和最大化。
cpp复制class Node {
public:
vector<Node*> path;
int pass;
Node() : path(26, nullptr), pass(0) {}
};
class Tire {
public:
Node* root;
Tire() { root = new Node(); }
void insert(string& word) {
Node* cur = root;
cur->pass++;
for(auto& c : word) {
if(!cur->path[c-'a']) {
cur->path[c-'a'] = new Node();
}
cur = cur->path[c-'a'];
cur->pass++;
}
}
int get_ans(string& word) {
Node* cur = root;
int res = 0;
for(auto& c : word) {
if(cur->path[c-'a']) {
cur = cur->path[c-'a'];
res += cur->pass;
} else break;
}
return res;
}
};
cpp复制signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n; cin >> n;
vector<string> a(2*n);
for(int i=0; i<2*n; i++) cin >> a[i];
sort(a.begin(), a.end());
Tire* t = new Tire();
for(int i=0; i<2*n; i++) {
if(i%2 == 0) t->insert(a[i]);
}
int ans = 0;
for(int i=0; i<2*n; i++) {
if(i%2) ans += t->get_ans(a[i]);
}
cout << ans << '\n';
return 0;
}
在实际比赛中,这类题目需要快速理解题意并找到合适的解题策略。建议平时多练习各种算法模板题,比赛时才能快速识别题目类型并套用合适的解法。