2025CCPC郑州邀请赛暨河南省赛个人补题DEFGHJM

GYM:Dashboard - 2025 National Invitational of CCPC (Zhengzhou), 2025 CCPC Henan Provincial Collegiate Programming Contest - Codeforces

六题七题尾铜,七题手速银,八题前排九题金

D:签到

// Code Start Here	
	
	int n;
	cin >> n;
	int n1 = n , n2 = 0;
	while(n)n2 += n%10 , n /= 10;
	if( ((int)(sqrt(n1))) * ((int)(sqrt(n1))) == n1 && ((int)(sqrt(n2))) * ((int)(sqrt(n2))) == n2)cout <<"Yes" << endl;
	else cout <<"No" <<endl;

H:

很好玩的一个题,题目也重点强调了“可达”这个概念,这个题有一个结论,就是1~n的所有点一定是联通的,所以直接输出区间长度即可

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;

#define point(x)  fixed << setprecision(x)
#define sz(x) ((int)(x.size()))

template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}

int32_t main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
// Code Start Here	
	
	int t;
	cin >> t;
	while(t--){
		int s , l , r;
		cin >> s >> l >> r;
		cout << r - l + 1 << endl;
	}
	return 0;
}

J:签到 暴力循环26次取最大值即可

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;

#define point(x)  fixed << setprecision(x)
#define sz(x) ((int)(x.size()))

template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}
int holes_cnt[26] = {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};
int32_t main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
// Code Start Here	
	
	string s;
	cin >> s;
	int max_val = 0;
	for(int i = 0;i<=26;i++){
		int now = 0;
		for(int j = 0;j<sz(s);j++){
			now += holes_cnt[((int)(s[j]-'A'+i)%26)];
		}
		max_val = max(max_val , now);
	}
	cout << max_val << endl;
	return 0;
}

M:判断联通可以使用并查集动态维护,最后再看一下连通块的数量

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;

#define point(x)  fixed << setprecision(x)
#define sz(x) ((int)(x.size()))

template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}
struct DSU {
	vector<int> fa, p, e, f;
	DSU(int n) {
		fa.resize(n + 1);
		iota(fa.begin(), fa.end(), 0);
		p.resize(n + 1, 1);
		e.resize(n + 1);
		f.resize(n + 1);
	}
	int get(int x) {
		while (x != fa[x]) {
			x = fa[x] = fa[fa[x]];
		}
		return x;
	}
	bool merge(int x, int y) { // 设x是y的祖先
		if (x == y) f[get(x)] = 1;
		x = get(x), y = get(y);
		e[x]++;
		if (x == y) return false;
		if (x < y) swap(x, y); // 将编号小的合并到大的上
		fa[y] = x;
		f[x] |= f[y], p[x] += p[y], e[x] += e[y];
		return true;
	}
	bool same(int x, int y) {
		return get(x) == get(y);
	}
	bool F(int x) { // 判断连通块内是否存在自环
		return f[get(x)];
	}
	int size(int x) { // 输出连通块中点的数量
		return p[get(x)];
	}
	int E(int x) { // 输出连通块中边的数量
		return e[get(x)];
	}
};
int32_t main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
// Code Start Here	
	
	int n , m;
	cin >> n >> m;
	DSU q(n);
	int ans = 0;
	for(int i = 1;i<=m;i++){
		int u , v;
		cin >> u >> v;
		if(q.same(u , v))ans++;
		q.merge(u , v);
	}
	set<int> st;
	for(int i = 1;i<=n;i++)st.insert(q.get(i));
	cout << ans + sz(st) - 1 << endl;
	return 0;
}

G:

一种比较容易想到的方法是分奇偶讨论,如下图

可以发现只有4是没答案的

然后直接模拟就可以了

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;

#define point(x)  fixed << setprecision(x)
#define sz(x) ((int)(x.size()))

template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}

int32_t main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
// Code Start Here	
	
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		if(n == 4)cout <<"-1" << endl;
		else if(n == 2)cout << 1 << " " <<2 << endl;
		else {
			if(n % 2 == 1){
				for(int i = 1;i<(n + 3)/2;i++)cout << i << " " << i + 1 << endl;
				int idx = (n + 3)/2+1;
				for(int i = 2;i<=(n + 3)/2-2;i++)cout << i << " " << idx++ <<endl;
			}
			else{
				for(int i = 1;i<(n + 4)/2;i++)cout << i << " " << i + 1 << endl;
				int idx = (n + 4)/2+1;
				for(int i = 2;i<=(n + 4)/2-3;i++)cout << i << " " << idx++ <<endl;
			}
		}
	}
	return 0;
}

F:

首先想到最优的情况是一旦走到终点联通的地方,马上停止药效,所以对于终点先跑一个BFS判断联通

其次思考对于如何去取最短的路径,第一想法是对于起点的连通块全部跑一遍BFS,但是时间复杂度不可行,其次思考如何优化,注意到最优的情况是一旦走到边界(即紧挨着#)才会使用药,所以取边界点,时间复杂度约为O((n + m) n *m) 不太可取

最后再思考怎么优化,对于起点跑一遍bfs,当越过边界(紧挨着#)的时候,在这个基础上++dis,最后判断什么时候到达终点,dijk也可取,时间复杂度为O(n * m )或者O(n * m * lognm)

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;

#define point(x)  fixed << setprecision(x)
#define sz(x) ((int)(x.size()))

template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}

int dx[] = {-1 , 0 , 1 , 0};
int dy[] = {0 , 1 , 0 , -1};

int32_t main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
// Code Start Here	
	
	int t;
	cin >> t;
	while(t--){
		int n , m;
		cin >> n >> m;
		auto inbound = [&](int x , int y){
			return x >= 0 && y < m && y >= 0 && x < n;
		};
		vector<vector<char>> g(n , vector<char>(m));
		for(int i = 0;i<n;i++){
			for(int j = 0;j<m;j++){
				cin >> g[i][j];
			}
		}
		auto bfs = [&](int x, int y)->vector<vector<int>>{
			vector<vector<int>> dis(n, vector<int>(m, INT_MAX));
			vector<vector<bool>> vis(n, vector<bool>(m,false));
			vector<pair<int, int>> p;
			queue<pair<int, int>> q;
			q.push({x, y});
			vis[x][y] = true;
			while (!q.empty()) {
				auto [x_, y_] = q.front();
				q.pop();
				p.emplace_back(x_, y_);
				for (int i = 0; i < 4; i++) {
					int nx = x_ + dx[i], ny = y_ + dy[i];
					if (inbound(nx, ny) && !vis[nx][ny] && g[nx][ny] == '.') {
						vis[nx][ny] = true;
						q.push({nx, ny});
					}
				}
			}
			for (auto [x, y] : p) {
				dis[x][y] = 0;
				q.push({x, y});
			}
			
			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 (inbound(nx, ny) && dis[nx][ny] == INT_MAX) {
						dis[nx][ny] = dis[x_][y_] + 1;
						q.push({nx, ny});
					}
				}
			}
			return dis;
		};
		vector<vector<int>> dis0 = bfs(0, 0);
		vector<vector<int>> dis1 = bfs(n - 1, m - 1);
		int ans = INT_MAX;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				ans = min(ans, dis0[i][j] + dis1[i][j] - 1);
			}
		}
		cout << max(ans , 0) << endl;
	}
	return 0;
}

E:

字符串排序 + 贪心配对
我们无法预知哪些是“引”、哪些是“根”,但最终要组成 n 对。所以不如直接将所有 2n 个字符串按字典序排序。然后每两个字符串分为一组(偶数是「引」,奇数是「根」)。因为字典序相近的字符串,公共前缀更可能更长。

	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());
	
	for (int i = 0; i < 2 * n; i++) {
		if (i % 2 == 0) {
			int v = 0;
			for (char c : a[i]) {
				int v = c - 'a';
				if (!ch[v][v]) ch[v][v] = idx++;
				v = ch[v][v];
			}
		}
	}
	
	i64 ans = 0;
	
	for (int i = 0; i < 2 * n; i++) {
		if (i % 2 == 1) {
			int v = 0;
			int res = 0;
			for (char c : a[i]) {
				int v = c - 'a';
				if (!ch[v][v]) break;
				v = ch[v][v];
				res++;
			}
			ans += res;
		}
	}
	
	cout << ans << endl;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值