【Codeforces题解+补题记录】 Codeforces Round #817 (Div. 4)

A. Spell Check

题意:给一个长度为n的字符串s,判断是否是"Timur"的正确拼写,此处正确拼写指为这几个字母的排列,且大小写严格。
题解:先判断输入的字符长度,如果不等于5说明不可能是Timur的正确拼写,当长度为5的时候遍历每一个字符存入map中,判断map的大小,如果map的大小不为5即其中有重复字符,不符合,当map中符合每一个字符都有且仅有一个时输出YES,其他情况为NO。
#include <bits/stdc++.h>

using namespace std;

void solve() {
	int n;
	scanf("%d", &n);
	string s;
	cin >> s;
	if(n != 5) {
		printf("NO\n");
		return;
	}
	map<char, int> mp;
	for(int i = 0; i <n;++i) {
		mp[s[i]]++;
	}
	if(mp.size() == 5) {
		if(mp['T'] == 1 && mp['i'] == 1 && mp['m'] == 1 && mp['r'] == 1 && mp['u'] == 1) {
			printf("YES\n");
			return;
		} 
	}
 	printf("NO\n");
}

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		solve();
	}
	return 0;
}

B.Colourblindness

题意:将B和G视作相同的字符,给定两个字符串,仅包含’R’、‘G’、'B’三种字符,判断两个字符串是否可以视为相同。
题解:当两个字符串中对应的字符相等或者一个为’G’另一个为’B’时可视作相等。
#include <bits/stdc++.h>

using namespace std;

void solve() {
	int n;
	string str1, str2;
	scanf("%d", &n);
	cin >> str1 >> str2;
	for(int i = 0; i < n; ++i) {
		if(!(str1[i] == str2[i] || str1[i] == 'G' && str2[i] == 'B' ||str2[i] == 'G' && str1[i] == 'B')) {
			printf("NO\n");
			return;
		}
	}
	printf("YES\n");
}

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		solve();
	}
	return 0;
}

C. Word Game

题意:三个人每个人分别写下n个长度为3的互不相同的字符串,如果一个字符串只有一个人写出来,那么这个人得到3分,如果一个字符串两个人都写了,那么两个人各的1分,如果三个人都写了同一个字符串,那么所有人不得分。
题解:因为每个人写的n个字符串时互不相同的,所以可以直接用map来存储每个字符串出现的次数,然后遍历每个人写的字符串,判断当这个字符串出现过两次时,代表两个人写了,那么这个人此时得1分,如果仅出现一次,代表只有他自己写了,那么这个人此时得3分,出现三次不得分可直接不写。最后分别输出每个人的得分。
#include <bits/stdc++.h>

using namespace std;

string a[4][1005];
int cnt[4];

void solve() {
	int n;
	scanf("%d", &n);
	memset(cnt, 0, sizeof(cnt));
	map<string, int> mp;
	for(int i = 0; i < 3; ++i) {
		for(int j = 0; j < n; ++j) {
			cin >> a[i][j];
			mp[a[i][j]]++;
		}
	}
	for(int i = 0; i < 3; ++i) {
		for(int j = 0; j < n; ++j) {
			if(mp[a[i][j]] == 1) {
				cnt[i]+=3;
			} else if(mp[a[i][j]] == 2) {
				cnt[i]+=1;
			}
		}
	}
	printf("%d %d %d\n", cnt[0], cnt[1], cnt[2]);
}

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		solve();
	}
	return 0;
}

D. Line

题意:n个人排队,仅包含L、R,L表示这个人向左看,R表示这个人向右看。每个人都有一个值表示向自己看的方向自己是第几个人。当最多变化的人数为k∈[1,n],k∈N个时,输出k取每个值时获得的最大值。
题解:为了使得值最大要得到的字符串为形似“RRRLLL”类型的,那么从两边往中间看,遍历从0到n / 2 - 1,当处于左半边的字符为’L’时可以更改一次,变为’R’,当处于右半边的字符为’R’时可以更改一次,变为’L’,当字符串被改为形似“RRRLLL”型或者奇数时“RRRLLLL”or“RRRRLLL”(这两种一样,中间的不管向哪边值都一样)后,如果k还不到n那么之后的都为这个最大值。
#include <bits/stdc++.h>

using namespace std;

void solve() {
	int n;
	long long cnt = 0;
	string s;
	scanf("%d", &n);
	cin >> s;
	for(int i = 0; i < n; ++i) {
		if(s[i] == 'L') {
			cnt += i;
		} else {
			cnt += n - i - 1;
		}
	}
	int k = 1;
	for(int i = 0; i < n / 2; ++i) {
		if(s[i] == 'L') {
			s[i] = 'R';
			cnt = cnt - i + n - i - 1;
			if(k != 1) printf(" ");
			k++;
			printf("%lld", cnt);
		}
		if(s[n - i - 1] == 'R') {
			s[n - i - 1] = 'L';
			cnt = cnt - n + (n - i - 1) + 1 + (n - i - 1);
			if(k != 1) printf(" ");
			k++;
			printf("%lld", cnt);
		}
	}
	if(k != n + 1){
		for(;k <= n; ++k) {
			if(k != 1)printf(" ");
			printf("%lld",cnt);
		}
	}
	printf("\n");
}

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		solve();
	}
	return 0;
}


补题

E.Counting Rectangles

题意:有n个矩形,每个矩形给出它的横向长度和纵向长度(不能旋转),q个查询,每个查询中分别给出矩形的最大和最小边界,给出所有能够被这两个边界框在中间(不能触碰边界,严格大于和严格小于)的矩形的面积之和。
题解:先将所有矩形视为从左上角重叠的矩形进行二维前缀和处理,最后根据查询范围给出答案。

例子如下:
在这里插入图片描述

当(hs,ws) = (2,5),(hb,wb) = (8,10)时
先通过前缀和处理得到a[i][j]=>该矩形覆盖的所有矩形的面积之和。
在这里插入图片描述
从题意看出,应当减掉的区域为从开头到(hb - 1, ws)和从开头到(hs, wb - 1)这两部分,最后把多减的加回去,而不是单纯的把(hb - 1,wb - 1)的前缀和减掉(hs,ws)的前缀和,因为在面积覆盖上会出现(3,2)和(4,3)这样因为纵长或者横长超出(hs,ws)的区域成为漏网之鱼。

没写出来的原因:先用了暴力判断,通过对给出的数据建立结构体存储其横长、纵长和面积,sort了一下,一个一个判断,在面积大于hb*wb的时候break,但是速度太慢了,tle了。后面用了前缀和,但最后输出的时候因为对题目理解不够透彻错掉了。
#include <bits/stdc++.h>

using namespace std;

long long rec[1005][1005];

long long a[1005][1005];

void solve() {
	int n, q;
	scanf("%d%d", &n, &q);
	int h, w;
	memset(rec, 0, sizeof(rec));
	memset(a, 0, sizeof(a));
	for(int i = 0; i < n; ++i) {
		scanf("%d%d", &h, &w);
		rec[h][w] += h * w;
	}
	for(int i = 1; i <= 1000; ++i) {
		for(int j = 1; j <= 1000; ++j) {
			a[i][j] = a[i - 1][j] + a[i][ j - 1] - a[i - 1][j - 1] + rec[i][j];
		}
	}
	int hs, ws, hb, wb;
	for(int i = 0; i < q; ++i) {
		scanf("%d%d%d%d", &hs, &ws, &hb, &wb);
		printf("%lld\n", a[hb - 1][wb - 1] - a[hb - 1][ws] - a[hs][wb - 1] + a[hs][ws]); // 赛时该处输出成了a[hb - 1][wb - 1] - a[hs][ws]
	}
}

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		solve();
	}
	return 0;
}

F. L-shapes

题意:输入一张由*代表黑色块,.代表白色块的格子图,判断是否符合每一个黑色块都组成正确的L形状。
题解:暴力判断,遍历整个图,判断每一个*是否符合以下条件(由题目的L-shape定义可以推得)
  1. 在它的周围8个位置中有两个"*",
  2. 这三个"*"的连成L的形状
#include <bits/stdc++.h>

using namespace std;

char a[55][55];
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
// right down up left
int dir2[4][2] = {-1, -1, 1, 1, -1, 1, 1, -1};
// lu rd ld ru
int n, m;

bool check(int x, int y) {
	if(x < 1 || x > n || y < 1 || y > m || a[x][y] != '*') {
		return false;
	}
	return true;
}

bool judge(int x, int y) {
	int vis[4] = {0};
	int vis2[4] = {0};
	int cnt = 0;
	int cnt2 = 0;
	for(int i = 0; i < 4; ++i) {
		int tx = x + dir[i][0];
		int ty = y + dir[i][1];
		if(check(tx, ty)) {
			vis[i] = 1;
			cnt++;
		}
	}
	if(cnt > 2 || cnt == 0) {
		return false;
	}
	if(cnt == 2) {
		if(vis[0] && vis[3] || vis[1] && vis[2]) {
			return false;
		}
	}
	for(int i = 0; i < 4; ++i) {
		int tx = x + dir2[i][0];
		int ty = y + dir2[i][1];
		if(check(tx, ty)) {
			vis2[i] = 1;
			cnt2++;
		}
	}
	if(cnt + cnt2 != 2) {
		return false;
	}
	if(cnt == 2) {
		return true;
	}
	if( (vis2[0] && (vis[2] || vis[3])) || (vis2[3] && (vis[3] || vis[1])) || (vis2[2] && (vis[2] || vis[0])) || (vis2[1] && vis[0] || vis[1]) ) {
		return true;
	} 
	return false;
}

void solve() {
	scanf("%d%d", &n, &m);
	getchar();
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= m; ++j) {
			scanf("%c", &a[i][j]);
		}
		getchar();
	}
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= m; ++j) {
			if(a[i][j] == '*') {
				if(!judge(i, j)) {
					printf("NO\n");
					return;
				}
			}
		}
	}
	printf("YES\n");
}

int main() {
	int t;
	scanf("%d", &t);
	while(t--) {
		solve();
	}
	return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值