比赛链接:Codeforces Round 937 (Div.4)

A. Stair, Peak, or Neither?

按照题目要求模拟即可。

时间复杂度: $O(1)$。

#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

按照题目要求模拟即可。

时间复杂度: $O(n^2)$。

#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

按照题目要求将 $24$ 小时制转换为 $12$ 小时制。这种涉及时间的题目,输入输出的时候用,scanfprintf 会比较方便一点。

时间复杂度: $O(1)$。

#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

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

时间复杂度: $O(\log n)$。

#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

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

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

时间复杂度: $O(n \sqrt n)$。

#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!

先判断是否存在这样的树。设总结点数为 $n=a+b+c$,树的边数一定是 $n-1$;另一方面,所有结点的子结点数量之和为 $2a+b$,也等于边数。所以必须满足 $2a+b=a+b+c-1$。化简可得 $c=a+1$。

如果不满足这个条件,就不可能构造出这样的树,直接输出 $-1$。

接下来考虑最小高度。为了让树尽量矮,应该尽可能把有 $2$ 个子结点的结点放在靠上的层,因为它们可以更快地扩展出更多位置。

时间复杂度: $O(\log a)$。

#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;
}