【周考】Round1 2024.7.6

Summary

Score: \(100+90+0+50+4=244\)


T1 减法操作

Algorithm: 思维

考虑对 \(n\) 分奇偶讨论:

  • 偶数:显然 最小质因子 为 \(2\),而每次减 \(2\) 后仍是偶数。所以偶数一定进行了 \(\dfrac n 2\) 次操作;
  • 奇数:因为是奇数,所以 最小质因子 一定也是奇数,减去后则变为偶数,接着可以转化为偶数处理。

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

code
#include <cstdio>
long long n, ans;
int main () {
	scanf("%lld", &n);
	if (n & 1) {
		for (long long i = 3; i * i <= n; i++)
			if (!(n % i))
				return printf("%lld", 1 + (n - i) / 2), 0;
		ans = 1;
	} else
		ans = n / 2;
	printf("%lld", ans);
	return 0;
}


T2 匹配数

Algorithm: 爆搜 / DP

考场思路:

感觉直接爆搜的时间复杂度实在是玄学,一下子想到了 贪心 (为什么不是 DP。。。

虽然考场上,对于 \(n=10\) 的数据,拍了 \(114514\) 多组(真,但是最后还是 WA\(90\text{pts}\)

设最终答案数组为 \(a\),对于 \(a[i]\),从贪心的角度分类讨论:

  • 对于 < \(a[i]=a[i-1]+1\)
  • 对于 >
    • \(a[i-1]\neq 0\)\(a[i]=0\)
    • \(a[i-1]=0\) :从 \(i\) 往前,直到第一个不等号的 \(a\) 都自加 \(1\)(当然还有很多细节,比如不等于的处理;
  • 对于 !
    • \(a[i-1]\neq 0\)\(a[i]=0\)
    • \(a[i-1]=0\)\(a[i]=1\)
  • 对于 =\(a[i]=a[i-1]\)

时间复杂度:\(O(nm)\)。其中 \(m\)> 的数量。

code for 贪心(90pts
#include <cstdio>
#include <cstring>
const int MAXN = 2005;
char s[MAXN];
int n, l, a[MAXN];
int main () {
	scanf("%s", s + 1), n = strlen(s + 1);
	a[0] = 1;
	for (int i = 1; i <= n; i++) {
		if (s[i] == '>') {
			a[i] = 0;
			if (a[i - 1] == 0) {
				for (int j = i - 1; j >= 0; j--) {
					a[j]++;
					if (s[j] == '!') {
						if (a[j] == a[j - 1]) {
							a[j]++;
							for (int k = j + 1; k <= i; k++) {
								if (s[k] == '=' || s[k] == '<') {
									a[k]++;
								} else if (s[k] == '!') {
									//根本就不可能。。。
								} else break;
							}
						}
						break;
					}
					if (s[j] == '<' && a[j - 1] < a[j]) break;
					if (s[j] == '>' && a[j - 1] > a[j]) break;
				}
			}
		}
		if (s[i] == '<') {
			a[i] = a[i - 1] + 1;
		}
		if (s[i] == '=') {
			a[i] = a[i - 1];
		}
		if (s[i] == '!') {
			if (a[i - 1] == 0) a[i] = 1;
			else a[i] = 0;
		}
	}
	for (int i = 0; i <= n; i++) putchar(a[i] + '0');
	return 0;
}
/*
Hacks:
<>!=<>!=<>!=<>!=<>!=
120112011201120112011

=!!!>
110120

==>>>
333210

 ><!=>
101220

<>>=>
132110

<<<<<<<<><<<<<<<<><<<<<<<<><<<<<<<<!
*/

爆搜

记录当前位填充的可能性(数字范围 & 不能取的值)

对于最后一位直接枚举输出即可,不需要在递归时对后一位进一步限制。

时间复杂度:\(O(\text{玄学})\),但是由于是从最小的开始搜,实际上是肯定跑不满的。

code
#include <cstdio>
#include <cstring>
#include <algorithm>
const int MAXN = 2005;
char s[MAXN];
int n, a[MAXN];
void dfs (int now, int l, int r, int no) {
	if (now > n) {
		for (int i = 0; i <= n; i++) putchar(a[i] + '0'); puts("");
		std::exit(0);
	}
	if (now == n) {
		for (int i = l; i <= r; i++) if (i != no) {
			a[now] = i;
			dfs(now + 1, 0, i - 1, -1);
		}
	}
	for (int i = l; i <= r; i++) if (i != no) {
		a[now] = i;
		if (s[now] == '>') dfs(now + 1, 0, i - 1, -1);
		if (s[now] == '<') dfs(now + 1, i + 1, 9, -1);
		if (s[now] == '!') dfs(now + 1, 0, 9, i);
		if (s[now] == '=') dfs(now + 1, i, i, -1);
	}
}
int main () {
	scanf("%s", s), n = strlen(s);
	dfs(0, 1, 9, -1);
	return 0;
}

T3 染色

将颜色相同的一段子区间称做「一段」

则至少 \(N-K\) 段,才能使多出来的 \(K-1\) 个格子即使放在一起也只有 \(K\) 对相邻的格子。

考虑满足「满足相邻的同色格子 恰为 \(K\) 对」 的方案数。

不考虑染色,则有

posted @ 2023-07-17 21:21  CloudWings  阅读(35)  评论(0编辑  收藏  举报