Codeforces Round 937 (Div.4)

比赛链接

A. Stair, Peak, or Neither?

时间限制:1秒        空间限制:256MB        输入:标准输入        输出:标准输出

问题描述

给定三个数字 a,b,c. 判断他们是否构成了一个 stair,peak,或者都不是.

  • 一个 stair 满足条件 a < b < c。
  • 一个 peak 满足条件 a < b > c。

输入格式

第一行包含一个整数 t(1 ≤ t ≤ 1000)表示测试用例的数量。

每个测试用例只有一行,包含三个数字 a,b,c(0 ≤ a,b,c ≤ 9)。

输出格式

对于每个测试用例,如果数字形成一个 stair,则输出 “STAIR”,如果数字形成一个 peak,则输出 “PEAK”,否则输出 “NONE”(输出字符串时不包含引号)。

输入输出样例

输入样例

        7\\ 1 \hspace{0.5em} 2 \hspace{0.5em} 3\\ 3 \hspace{0.5em} 2 \hspace{0.5em} 1\\ 1 \hspace{0.5em} 5 \hspace{0.5em} 3\\ 3 \hspace{0.5em} 4 \hspace{0.5em} 1\\ 0 \hspace{0.5em} 0 \hspace{0.5em} 0\\ 4 \hspace{0.5em} 1 \hspace{0.5em} 7\\ 4 \hspace{0.5em} 5 \hspace{0.5em} 7\\

输出样例

        STAIR\\ NONE\\ PEAK\\ PEAK\\ NONE\\ NONE\\ STAIR\\

代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, a, b, c;
    cin >> n;
    while (n--) {
        cin >> a >> b >> c;
        if (a < b && b < c) printf("STAIR\n");
        else if (a < b && b > c) printf("PEAK\n");
        else printf("NONE\n");
    }
    return 0;
}

B. Upscaling

时间限制:1秒        空间限制:256MB        输入:标准输入        输出:标准输出

题目描述

给定一个整数 n。输出一个大小为 2n \times 2n 的棋盘,由大小为 2 × 2 的方块组成,交替使用 '#' 和 '.',并且左上角的单元格为 '#'。

输入格式

第一行包含一个整数 t(1 ≤ t ≤ 20)表示测试用例的数量。

每个测试用例只有一行,包含一个整数 n(1 ≤ n ≤ 20),表示你需要输出边长为 2n 的棋盘。

输出格式

对于每个测试用例,输出 2n 行,每行包含 2n 个不带空格的字符。按照题目描述的方式输出棋盘。在测试用例之间不要输出空行。

输入输出样例

输入样例

        4\\ 1\\ 2\\ 3\\ 4\\

输出样例

        \#\#\\ \#\#\\ \#\#.\hspace{0.3em}.\\ \#\#.\hspace{0.3em}.\\ .\hspace{0.3em}.\#\#\\ .\hspace{0.3em}.\#\#\\ \#\#.\hspace{0.3em}.\#\#\\ \#\#.\hspace{0.3em}.\#\#\\ .\hspace{0.3em}.\#\#.\hspace{0.3em}.\\ .\hspace{0.3em}.\#\#.\hspace{0.3em}.\\ \#\#.\hspace{0.3em}.\#\#\\ \#\#.\hspace{0.3em}.\#\#\\ \#\#.\hspace{0.3em}.\#\#.\hspace{0.3em}.\\ \#\#.\hspace{0.3em}.\#\#.\hspace{0.3em}.\\ .\hspace{0.3em}.\#\#.\hspace{0.3em}.\#\#\\ .\hspace{0.3em}.\#\#.\hspace{0.3em}.\#\#\\ \#\#.\hspace{0.3em}.\#\#.\hspace{0.3em}.\\ \#\#.\hspace{0.3em}.\#\#.\hspace{0.3em}.\\ .\hspace{0.3em}.\#\#.\hspace{0.3em}.\#\#\\ .\hspace{0.3em}.\#\#.\hspace{0.3em}.\#\#\\

代码

#include <bits/stdc++.h>
using namespace std;

int n, t;

inline int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') x = x * 10 +c - '0', c = getchar();
    return x * f;
}

int main() {
    t = read();
    while (t--) {
        n = read();
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if ((i + j) % 2 == 0) printf("##");
                else printf("..");
            }
            printf("\n");
            for (int j = 1; j <= n; j++) {
                if ((i + j) % 2 == 0) printf("##");
                else printf("..");
            }
            printf("\n");
        }
    }
    return 0;
}

C. Clock Conversion

时间限制:1秒        空间限制:256MB        输入:标准输入        输出:标准输出

题目描述

给定24小时制的时间,输出相应的12小时制时间。

  • 24小时制将一天分为24小时,从00:00到23:59,每小时有60分钟。
  • 12小时制将一天分为两半:上半部分是AM,下半部分是PM。在每半部分,小时按照 12, 01, 02, 03,…,11 的顺序编号。每个小时有 60 分钟,从 00 : 00 到 11 : 59 为AM,从 12 : 00 到 23 : 59 为 PM。

输入格式

第一行包含一个整数 t(1 ≤ t ≤ 1440) 表示测试用例的数量。

每个测试用例只有一行,包含一个长度为 5 的字符串 s,格式为 hh : mm,表示 24 小时制中的一个有效时间。hh 代表小时,取值范围为 00 到 23,而 mm 代表分钟,取值范围为 00 到 59。

输入的时间总是一个有效的24小时制时间。

输出格式

对于每个测试用例,输出两个字符串,用空格分隔("hh:mm AM" 或 "hh:mm PM"),它们是测试用例中提供的时间的 12 小时制等价时间(不包含引号)。

你应该按照指定的格式输出时间;特别说明,不要移除前导零。

输入输出样例

输入样例

        11\\ 09:41\\ 18:06\\ 12:14\\ 00:59\\ 00:00\\ 14:34\\ 01:01\\ 19:07\\ 11:59\\ 12:00\\ 21:37\\

输出样例

        09:41 \hspace{0.5em} AM\\ 06:06 \hspace{0.5em} PM\\ 12:14 \hspace{0.5em} PM\\ 12:59 \hspace{0.5em} AM\\ 12:00 \hspace{0.5em} AM\\ 02:34 \hspace{0.5em} PM\\ 01:01 \hspace{0.5em} AM\\ 07:07 \hspace{0.5em} PM\\ 11:59 \hspace{0.5em} AM\\ 12:00 \hspace{0.5em} PM\\ 09:37 \hspace{0.5em} PM\\

思路

按照题目要求将24小时制转换为12小时制。

这种涉及时间的题目,输入输出的时候用 scanf 和 printf 方便一点。

代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int h, m;
        char c;
        scanf("%d:%d", &h, &m);
        if (h < 12) {
            c = 'A';
            if (h == 0) h = 12;
        }
        else {
            c = 'P';
            if (!(h == 12)) h -= 12;
        }
        printf("%02d:%02d %cM\n", h, m, c); // 如果小时或时间为一位数,在前面补零
    }
    return 0;
}

D. Product of Binary Decimals

时间限制:3秒        空间限制:256MB        输入:标准输入        输出:标准输出

题目描述

如果一个正整数的十进制表示中的所有数字都是 0 或 1,则将其称为二进制十进制数。例如, 1010111 是一个二进制十进制数,而 10201 和 787788 则不是。

给定一个数 n,你需要判断是否可能将 n 表示为一些(不一定不同的)二进制十进制数的乘积。

输入格式

第一行包含一个整数 t(1 ≤ t ≤ 5 \times 10^{4})表示测试用例的数量。

每个测试用例只有一行,包含一个整数 n (1 ≤ n ≤ 10^{5})。

输出格式

对于每个测试用例,如果 n 可以表示为二进制十进制数的乘积,则输出 "YES"(不包含引号),否则输出 "NO"(不包含引号)。

你可以以任何形式输出 "YES" 和 "NO"(例如,字符串 "yES"、"yes" 和 "Yes" 都是正确答案)。

输入输出样例

输入样例

        11\\ 121\\ 1\\ 14641\\ 12221\\ 10110\\ 100000\\ 99\\ 112\\ 2024\\ 12421\\ 1001\\

输出样例

        YES\\ YES\\ YES\\ YES\\ YES\\ YES\\ NO\\ NO\\ NO\\ NO\\ YES\\

注释

这些测试案例可以表示为二进制小数的乘积,如下所示:

  • 121 = 11 × 11。
  • 1 = 1 已经是一个二进制小数。
  • 14641 = 11 × 11 × 11 × 11。
  • 12221 = 11 × 11 × 101。
  • 10110 = 10110 已经是一个二进制小数。

思路

由于小于 10^{5} 的 "binary decimal" 数比较少,所以可以直接用a数组列举出所有 "binary decimal" 数。然后再利用 dfs 判断给出数字能否由 "binary decimal" 数的乘积组成。

代码

#include <bits/stdc++.h>
using namespace std;

int t, n, flag;
int a[]={ 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111, 10000, 10001, 10010, 10011, 10100, 10101, 10110, 10111, 11000, 11001, 11010, 11011, 11100, 11101, 11110, 11111 };

inline int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') x = x * 10 +c - '0', c = getchar();
    return x * f;
}

void dfs(int x) {
    if (x == 1 || flag == 1) { flag = 1; return; }
    for (int i = 0; i < 30; i++) {
        if (x % a[i] == 0) dfs(x / a[i]);
    }
}


int main() {
    t = read();
    while (t--) {
        n = read();
        flag = 0;
        dfs(n);
        if (flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

E. Nearly Shortest Repeating Substring

时间限制:2秒        空间限制:256MB        输入:标准输入        输出:标准输出

题目描述

给定一个长度为 n 的由小写拉丁字符组成的字符串 s。找到最短的字符串 k 的长度,使得可以将若干个(可能是一个)k 连接在一起形成一个与 s 相同长度的字符串,并且最多有一个不同的字符。

更严谨地说,找到最短的字符串 k 的长度,使得对于某个正整数 x,字符串 s 和 c = k + ⋯ + k(重复 x 次)有相同的长度,并且对于最多一个 i,c_{i} \not= s_{i}(即存在 0 或 1 个这样的位置)。

输入格式

第一行包含一个整数 t(1 ≤ t ≤ 10^{3})表示测试用例的数量。

每个测试用例的第一行包含一个整数 n(1 ≤ n ≤ 2 \times 10^{5})表示字符串 s 的长度。

每个测试用例的第二行包含一个由小写拉丁字符组成的字符串 s。

所有测试用例中 n 的总和不超过 2 \times 10^{5}

输出格式

对于每个测试用例,输出满足题目中条件的最短字符串 k 的长度。

输入输出样例

输入样例

        5\\ 4\\ abaa\\ 4\\ abba\\ 13\\ slavicgslavic\\ 8\\ hshahaha\\ 20\\ stormflamestornflame

输出样例

        1\\ 4\\ 13\\ 2\\ 10\\

注释

在第一个测试案例中,你可以选择 k = a,并且 k + k + k + k = aaaa,这只与 s 的第二个位置不同。

在第二个测试案例中,你不能选择长度为 1 或 2 的 k。我们可以选择 k = abba,这与 s 相等。

思路

  • 从原字符串的头部和尾部分别枚举字符串 k,再去判断这个字符串 k 能不能通过重复来组成字符串 s,使得最多有一个字符不同。
  • 优化:只有当字符串 k 的长度能够整除字符串 s 长度 n 的时候 k 才有可能是组成 s 的最短子串,所以只有当字符串 k 的长度能够整除字符串 s 长度 n 的时候需要验证。
  • 可能有人会问:为什么要分别从原字符串的头部和尾部分别枚举?不能只从一头枚举吗?

根据题目意思我们可以得出,如果头部或尾部的字符串 k1,k2 可以通过重复组成字符串 s,那么 k1,k2可能存在一下几种情况:

  1. k1 和 k2相等。当 k1 和 k2 相等的时候,只从一端进行枚举跟从两端进行枚举结果是一样的。
  2. k1 和 k2 相差一个字符。当 k1 和 k2 相差一个字符的时候,只从一端进行枚举结果可能会出现错误。例如样例里的字符串 hshahaha ,从两端枚举的时候结果是 2,从一端枚举的结果是 4。这是因为 hshahaha 这个字符串的 k = "ha",而只从头枚举不可能出现这样的 k 字符串。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int t, n, ans;
string s1;

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}

int main() {
	t = read();
	while (t--) {
		n = read();
		ans = n;
		cin >> s1;
		for (int i = 1; i <= n / 2; i++) {
			if (n % i != 0) continue;
			string s2 = s1.substr(0, i);
			int flag = 0;
			for (int j = 0, k = 0; j < n; j++, k = (k + 1) % i) {
				if (s1[j] != s2[k]) flag++;
				if (flag > 1) break;
			}
			if (flag <= 1) ans = min(ans, i);
			s2 = s1.substr(n - i, i), flag = 0;
			for (int j = 0, k = 0; j < n; j++, k = (k + 1) % i) {
				if (s1[j] != s2[k]) flag++;
				if (flag > 1) break;
			}
			if (flag <= 1) ans = min(ans, i);
		}
		printf("%d\n", ans);
	}
    return 0;
}

F. 0, 1, 2, Tree!

时间限制:2秒        空间限制:256MB        输入:标准输入        输出:标准输出

题目描述

找到一棵有 a + b + c 个节点的有根树的最小高度,该树满足以下条件:

  • a 个节点恰好有 2 个子节点,
  • b 个节点恰好有 1 个子节点,
  • c 个节点恰好没有子节点。

如果不存在这样的树,则输出 -1。

上面的树是以顶部顶点为根,并且每个顶点上标有它的子节点数量。这里 a = 2,b = 1,c = 3,高度为 2。 

有根根树是一个无环的连通图,其中有一个特殊的顶点称为根。在一棵有根树中,任意两个由一条边连接的顶点中,一个是父节点(更接近根的节点),另一个是子节点。

树中两个顶点之间的距离是它们之间最短路径上的边数。有根树的高度是从一个顶点到根的最大距离。

输入格式

第一行包含一个整数 t(1 ≤ t ≤ 10^{4})表示测试用例的数量。

每个测试用例的只有一行,包含三个整数 a,b 和 c ( 0 ≤ a,b,c ≤ 10^{5};1 ≤ a + b + c)。

所有测试用例中 a + b + c 的总和不超过 3 \times 10^{5}

输出格式

对于每个测试用例,如果不存在这样的树,则输出 -1。否则,输出一个整数,表示满足题目中条件的树的最小高度。

输入输出样例

输入样例

        10\\ 2 \hspace{0.5em} 1 \hspace{0.5em} 3\\ 0 \hspace{0.5em} 0 \hspace{0.5em} 1\\ 0 \hspace{0.5em} 1 \hspace{0.5em} 1\\ 1 \hspace{0.5em} 0 \hspace{0.5em} 2\\ 1 \hspace{0.5em} 1 \hspace{0.5em} 3\\ 3 \hspace{0.5em} 1 \hspace{0.5em} 4\\ 8 \hspace{0.5em} 17 \hspace{0.5em} 9\\ 24 \hspace{0.5em} 36 \hspace{0.5em} 48\\ 1 \hspace{0.5em} 0 \hspace{0.5em} 0\\ 0 \hspace{0.5em} 3 \hspace{0.5em} 1\\

输出样例

        2\\ 0\\ 1\\ 1\\ -1\\ 3\\ 6\\ -1\\ -1\\ 3\\

注释

第一个测试用例如题目中所示。可以证明,无法得到小于 2 的高度的有根树。

在第二个测试用例中,你可以形成一个只有一个顶点且没有边的树。它的高度为 0,显然是最优的。

在第三个测试用例中,你可以形成一个由单条边连接的两个顶点的树。它的高度为 1,显然是最优的。

思路

代码

#include <bits/stdc++.h>
using namespace std;

int t, a, b, c;

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}

int main() {
	t = read();
	while (t--) {
		a = read(), b = read(), c = read();
		if (c != a + 1) printf("%d\n", -1);
		else if (a == 0) printf("%d\n", b);
		else if (b == 0) { int oup = log2(a) + 1; printf("%d\n", oup); }
		else {
			int num = 1, oup = log2(a) + 1, res;
			while (1) {
				if (a <= num) {
					res = a + num;
					b -= (num - a);
					num *= 2;
					break;
				}
				a -= num;
				num *= 2;
			}
			if (b <= 0) printf("%d\n", oup);
			else printf("%d\n", oup + (b + res - 1) / res);
		}
	}
    return 0;
}

G. Shuffling Songs 

时间限制:3秒        空间限制:256MB        输入:标准输入        输出:标准输出

题目描述

Vladislav 有一个由 n 首歌组成的播放列表,编号从 1 到 n。第 i 首歌有流派 g_{i} 和作者 w_{i}。他想要制作一个播放列表,使得每对相邻的歌曲要么具有相同的作者,要么属于相同的流派(或者两者都是)。他将这样的播放列表称为令人兴奋的,g_{i} 和 w_{i} 都是长度不超过 10^{4} 的字符串。

要想用所有歌曲制作出令人兴奋的播放列表并不总是可能的,因此洗牌过程分为两个步骤。首先,删除部分歌曲(可能为零),然后重新排列播放列表中剩余的歌曲,使其更加精彩。

由于 Vladislav 不喜欢从他的播放列表中删除歌曲,他希望制作播放列表时尽量少地进行删除。帮助他找到需要执行的最小删除数量,以便能够重新排列其余的歌曲以制作令人兴奋的播放列表。

输入格式

输入的第一行包含一个整数 t(1 ≤ t ≤ 1000),表示测试用例的数量。接下来是每个测试用例的描述。

每个测试用例的第一行包含一个整数 n(1 ≤ n ≤ 16),表示原始播放列表中歌曲的数量。

然后是 n 行,其中第 i 行包含两个小写字母字符串 g_{i} 和 w_{i}(1 ≤ |g_{i}||w_{i}| ≤ 10^{4}),表示第 i 首歌曲的流派和作者。其中 |g_{i}| 和 |w_{i}| 是字符串的长度。

所有测试用例的 2^{n} 的总和不超过 2^{16}

所有测试用例中 |g_{i}| + |w_{i}| 的总和不超过 4 \times 10^{5}

输出格式

对于每个测试用例,输出一个整数,表示使得结果播放列表可以制作为令人兴奋的所需的最小移除数量。

输入输出样例

输入样例

        4\\ 1\\ pop \hspace{0.5em} taylorswift\\ 4\\ electronic \hspace{0.5em} themotans\\ electronic \hspace{0.5em} carlasdreams\\ pop \hspace{0.5em} themotans\\ pop \hspace{0.5em} irinarimes\\ 7\\ rap \hspace{0.5em} eminem\\ rap \hspace{0.5em} drdre\\ rap \hspace{0.5em} kanyewest\\ pop \hspace{0.5em} taylorswift\\ indierock \hspace{0.5em} arcticmonkeys\\ indierock \hspace{0.5em} arcticmonkeys\\ punkrock \hspace{0.5em} theoffspring\\ 4\\ a \hspace{0.5em} b\\ c \hspace{0.5em} d\\ e \hspace{0.5em} f\\ g \hspace{0.5em} h\\

输出样例

        0\\ 0\\ 4\\ 3

注释

在第一个测试用例中,播放列表已经是令人兴奋的。

在第二个测试用例中,如果你有歌曲的顺序为 4,3,1,2,那么它是令人兴奋的,所以你不需要移除任何歌曲。

在第三个测试用例中,你可以移除歌曲 4,5,6,7。然后,具有顺序 1,2,3 的播放列表是令人兴奋的。

思路

代码

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值