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定义可以推得)
- 在它的周围8个位置中有两个"*",
- 这三个"*"的连成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;
}