CDZSC_2022寒假个人训练赛21级(8)题解

  • 简单
    • F 简单dp、贪心
    • G 字符串
    • H
  • 中等
    • A 模拟
    • C 并查集
    • D 最小生成树
    • E 模拟
  • 困难
    • B bfs

A Extract Numbers CodeForces - 600A

题意

给定一个字符串,字符';' 和 ','将串分开,每部分是一个单词,若出现中间为空的情况(连续两个分隔符),则认为中间的单词是空格。若单词是整数(不能有前导0),则放在串a里面,反之放在串b里面。在a,b串中,单词用','分开。若无单词是整数,a串为"-",若无单词是非整数,b串为"-"。最后输出a串和b串,如a串(b串)不是"-",输出时用""括起。

题解

模拟

AC代码

bool check(string s) {
	if (s == "") return 0;
	if (s[0] == '0' && s.size() > 1) return 0;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] >= '0' && s[i] <= '9') continue;
		return 0;
	}
	return 1;
}
 
int main () {
	string s; cin >> s;
	s += ",";
	int now = 0;
	string a = "\"", b = "\"";
	while (now < s.size()) {
		string t;
		while (now < s.size() && s[now] != ',' && s[now] != ';') t.push_back(s[now]), now++;
		now++;
		if (check(t)) {
			a += t + ",";
		} else {
			b += t + ",";
		}
	}
	a.pop_back(), b.pop_back();
	a += "\"", b += "\"";
	if (a == "\"") a = "-";
	if (b == "\"") b = "-";
	cout << a << endl << b << endl;
	return 0;
}

B Kilani and the Game CodeForces - 1105D

题意

一个棋盘,\(p\)种颜色已经涂了一些区域,每种颜色有扩散速度 \(s_i\) ,每轮按顺序依次扩展,扩展区域为已有区域任意格走 \(s_i\) 次能到达的可涂色格子,且不能穿过其他颜色与不可涂色格,棋盘无可涂色区域游戏结束,输出各种颜色格子数。

题解

两个bfs模拟就好,除了麻烦点,难度其实挺低,如果bfs已经学了,但代码写不出来,属于基本功不行。
这题cf 分数高纯属于cf时间太短,上面的A题也一样,在acm赛制下 cf 对长代码的题分数虚高。

AC代码

#include<iostream>
#include<algorithm>
#include<set>
#include<stdio.h>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
struct  node{
	int x, y, step;
	node(int a,int b,int c):x(a),y(b),step(c){}
};

int n, m,p;
int s[10];
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };

char plat[1005][1005];
queue<node> pq[10],q;
int ans[10];
void bfs(int num) {

	while (q.size()) {
		node tmp = q.front();
		q.pop();
		if (tmp.step == 0) {
			tmp.step = s[num];
			pq[num].push(tmp);
			continue;
		}
		for (int i = 0; i < 4; i++) {
			int x = tmp.x + dx[i];
			int y = tmp.y + dy[i];
			if (x < 0 || x >= n || y < 0 || y >= m || plat[x][y] != '.')continue;
			plat[x][y] = num+'0';
			q.push(node(x, y, tmp.step - 1));
		}
		

	}

}


bool act(int x) {

	while (pq[x].size()) {
		q.push(pq[x].front());
		pq[x].pop();
	}
	bfs(x);
	return pq[x].size();
}


int main() {
	
	scanf("%d%d%d", &n, &m, &p);

	for (int i = 1; i <= p; i++) 
		scanf("%d", s + i);
	for (int i = 0; i < n; i++) 
		scanf("%s", plat + i);
	
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if ('1'<=plat[i][j]&& plat[i][j] <='9') {
				pq[plat[i][j] - '0'].push(node(i, j, s[plat[i][j] - '0']));

			}
		}
	}

	while (1) {
		int flag = 1;
		for (int i = 1; i <= p; i++) {
			if (act(i))flag = 0;
		}
		if (flag)break;
	}
	
	for(int i=0;i<n;i++)
		for (int j = 0; j < m; j++) {
			if ('1' <= plat[i][j]&&plat[i][j] <= '9') {
				ans[plat[i][j] - '0']++;
			}
		}
	for (int i = 1; i <= p; i++)
		printf("%d ", ans[i]);

	return 0;

}

C Wireless Network POJ - 2236

题意

每台电脑只能与距离它不超过 d 米的其它电脑直接通信。但每台电脑可被看作其它两台电脑的通信中转点,也就是说,如果电脑 A 和电脑 B 可以直接通信,或存在一台电脑 C 既可与 A 也可与 B 通信,那么电脑 A 和电脑 B 之间就能够通信。
在处理网络修复的过程中,工作人员们在任何一个时刻,可以执行两种操作:维修一台电脑,或测试两台电脑是否能够通信。请您找出全部的测试操作。

题解

并查集,维修操作的时候,将维修的节点和所有可连节点连接,查询就直接查询是否在同一个集合。
set 启发式合并也可以做,反正只要能快速维护集合的合并,并且快速查找是否存在对应元素的数据结构都可以做。只不过并查集比较好写,也简单。

AC代码

#include<iostream>
#include<math.h>
using namespace std;

int s[1005][2];
int l[1005];
int h[1005];
int d;
void init(int n) {
	for (int i = 1; i <= n; i++)
		l[i] = i;
}

int find(int x) {
	return x == l[x] ? x : find(l[x]);
}

void merge(int a,int b) {
	a = find(a);
	b = find(b);
	l[a] = b;
}
bool equal(int a, int b) {
	return find(a) == find(b);
}

bool near(int a, int b) {
	double dx = s[a][0] - s[b][0];
	double dy = s[a][1] - s[b][1];
	double dis = sqrt(dx*dx + dy * dy);
	return dis <= d;
}

int main() {
	int n, k=0;
	scanf("%d%d", &n, &d);
	init(n);
	for (int i = 1; i <= n; i++) {
		scanf("%d%d", s[i],s[i]+1);
	}

	char c;
	while (~scanf("%c", &c)) {
		if (c == 'O') {
			int x;
			int flag = 1;
			scanf("%d", &x);
			for (int i = 0; i < k; i++) {
				if (near(x, h[i])) {
					merge(x, h[i]);
				}
			}
			h[k++] = x;

		}
		else if (c == 'S') {
			int a, b;
			scanf("%d%d", &a, &b);
			if (equal(a, b)) 
				printf("SUCCESS\n");
			else printf("FAIL\n");
		}
	}

}

D Jungle Roads POJ - 1251

题意

有一个旅游区,旅游区有很多的景点,景点间需要开通缆车,使得任意两个景点可以互相到达。现在给出一些点间的缆车线路制造成本,两个景点之间可能有多重制造方式。问最少的花费是多少。

题解

最小生成树裸题。

AC代码

#include<iostream>
#include<algorithm>
using namespace std;

struct edge {
	int u, v, w;

	bool operator<(edge x) {
		return w < x.w;
	}
};
int s[100];
int h[100];
edge e[100];

void init(int n) {
	for (int i = 0; i < n; i++) {
		s[i] = i;
		h[i] = 0;
	}
}

int find(int x) {
	if (x != s[x])s[x] = find(s[x]);
	return s[x];
}

void near(int a, int b) {
	a = find(a), b = find(b);
	if (h[a] == h[b]) {
		s[b] = a;
		h[a] = h[a] + 1;
	}
	else {
		if (h[a] < h[b])s[a] = b;
		else s[b] = a;
	}
}

int main() {
	int n;
	while (scanf("%d", &n), n) {
		init(n);
		int k = 0,ans=0;
		for (int i = 0; i < n - 1; i++) {
			char a, b;
			int m,x;
			cin >> a >> m;
			while (m--) {
				cin >> b >> x;
				e[k].u = a-'A';
				e[k].v = b-'A';
				e[k++].w = x;
			}
		}
		sort(e, e + k);

		for (int i = 0; i < k; i++) {
			int a = find(e[i].u), b = find(e[i].v);
			if (a == b)continue;
			s[b] = a;
			ans += e[i].w;
		}
		printf("%d\n", ans);
	}

	return 0;
}

E s-palindrome CodeForces - 691B

题意

判断字符串是否左右镜像对称

题解

AHIMOoTUVvWwXxY 这些字符本身是对称的,由这些字符构成的子串都能左右镜像对称。
bd、 pq ,这些字符成对对称,左右两边如果出现对应的也能对称

AC代码

char s[N];
char mirror[]="AHIMOoTUVvWwXxY";
char sym[]="bdpq";

bool isSym(char a,char b){
	for(int i=0;s[i];i++){
		if(!s[i+1])continue;
		if(sym[i]==a&&sym[i+1]==b)
			return 1;
		if(sym[i+1]==a&&sym[i]==b)
			return 1;
	}
	return 0;
}
bool in(char *s,char c){
	for(int i=0;s[i];i++)
		if(s[i]==c)return 1;
	return 0;
}
int main(){

	scanf("%s",s);
	int flag=1,n=0;
	for(;s[n];n++){
		if(!in(mirror,s[n])&&!in(sym,s[n])){
			flag=0;
			break;
		}
	}
	for(int i=0;i<n/2;i++){
		if(!(isSym(s[i],s[n-1-i])||(in(mirror,s[i])&&s[i]==s[n-1-i])))
			flag=0;
		if(flag==0)break;
	}
	if(flag&&n&1)flag=in(mirror,s[n/2]);
	printf("%s\n",flag?"TAK":"NIE");



	scanf(" ");

}

F The Way to Home CodeForces - 910A

题意

一只青蛙现在在一个数轴上,它现在要从点 1 跳到点 \(n\) ,它每次可以向右跳不超过 \(d\) 个单位。比如,它可以从点 \(x\) 跳到点 \(x+a(1≤a≤d)\)

题解

简单dp或者贪心,或者dfs,反正数据就100,随便做都行。

AC代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;

int dp[105];
char s[105];
int main() {
	int n, m;
	memset(dp, 0x3f, sizeof dp);
	scanf("%d%d%s", &n, &m, s + 1);
	dp[1] = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m && j + i <= n; j++)
			if (s[i + j] == '1')
				dp[i + j] = min(dp[i + j], dp[i] + 1);

	printf("%d\n", dp[n] == 0x3f3f3f3f ? -1 : dp[n]);
	return 0;
}

G Generate Login CodeForces - 909A

题意

给定两个用空格分隔的字符串,分别取两字符串的任意非空前缀,将两前缀合并为一个新的字符串,求可行字典序最小的字符串。

题解

因为字典序最小所以尽量要短,先输出必须要有的\(a[0]\),然后根据字典序号大小来判断是直接输出\(b[0]\)然后结束还是继续输出\(a\)的后续字符

AC代码

#include<iostream>
#include<cmath>
using namespace std;
char a[20],b[20];
int main(){

	int n,r;
	scanf("%s%s",a,b);
	printf("%c",a[0]);
	for(int i=1;a[i];i++){
		if(a[i]>=b[0]){
			printf("%c",b[0]);
			return 0;
		}
		printf("%c",a[i]);
	}
	printf("%c",b[0]);
	return 0;
}

H Tricky Alchemy CodeForces - 912A

题意

要生产一个黄色球,需要两颗黄色晶体,生产绿色需要一黄一蓝,生产蓝色,需要三蓝。
给出黄色晶体和蓝色的数量,和要生产的球,问还需要多少晶体。

题解

AC代码

int main() {
	ll a, b, x, y, z,aa,bb;
	scanf("%lld%lld%lld%lld%lld", &a, &b, &x, &y, &z);
	aa = x * 2 + y;
	bb = y + z * 3;
	ll ans = 0;
	if (aa - a > 0)ans += aa - a;
	if (bb - b > 0)ans += bb - b;
	printf("%lld\n", ans);
	return 0;
}
posted @ 2022-02-12 16:59  _comet  阅读(167)  评论(0编辑  收藏  举报