『模拟赛题解』9.24 NOIP 模拟赛

9.24 NOIP 模拟赛

T1. 质因数

Description

给你 \(n\) 个数,求出每个数分解质因数后不同的质因数数量(以下简称 \(f(x)\))。

Solution

考场思路

首先先把 \(1 \sim 10^6\) 以内的质数全部筛出来,则这些质数的 \(f = 1\)

经过一系列的推导,我得到了一个奇怪的结论:

\[f_i= \left\{\begin{matrix} f_{\frac{i}{k_i}} & \dfrac{i}{k_i} \mod j =0 \\ f_{k_i} + f_{\frac{i}{k_i}} & \mathrm {Otherwise} \end{matrix}\right. \]

其中 \(k_i\)\(i\) 最小的质因数。

最终得分只有 \(40\) pts。但好像这个式子已经很接近正解了。

正解

正解如下:

\[f_i= \left\{\begin{matrix} f_{\frac{i}{k_i}} & k_i = k_{\frac{i}{k_i} } \\ f_{\frac{i}{k_i}} + 1 & \mathrm{Otherwise} \end{matrix}\right. \]

\(k_i\) 含义同上,特别的,\(k_1 = 0\)

\(k_i\) 怎么处理呢?其实就是线性筛的一个小变种。

Complexity

时间复杂度:朴素筛法:\(O(n + \max a_i \times log_2 \max a_i)\),线性筛法:\(O(n + \max a_i)\)\(a_i\) 是输入的数)

空间复杂度:\(O(n)\)

Code

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

const int maxn = 1e6;

int n;
int f[maxn + 5], x[maxn + 5], k[maxn + 5], p[maxn + 5];

int read()
{
	char ch;
	int ans = 0;
	ch = getchar();
	while (ch < '0' || ch > '9')
		ch = getchar();
	while (ch >= '0' && ch <= '9')
	{
		ans = ans * 10 + ch - '0';
		ch = getchar();
	}
	return ans;
}

int main()
{
	freopen("easy.in", "r", stdin);
	freopen("easy.out", "w", stdout);
	n = read();
	for (int i = 1; i <= n; i ++)
		x[i] = read();
	memset(p, 1, sizeof(p));
	p[1] = true;
	k[1] = 0;
	for (int i = 2; i <= maxn; i ++)
	{
		if (p[i])
		{
			for (int j = 1; i * j <= maxn; j ++)
			{
				if (p[i * j])
					k[i * j] = i;
				p[i * j] = 0;
			}
		}
		f[i] = f[i / k[i]];
		if (k[i / k[i]] != k[i])
			f[i] ++;
	}

	for (int i = 1; i <= n; i ++)
		cout << f[x[i]] << '\n';
	return 0;
}

T2. 编码

Description

每个数字字符串都可以被表示为 \(b_1\)\(c_1\)\(b_2\)\(c_2\)\(\dots\)\(b_n\)\(c_n\)

\(b_1, c_1, b_2, c_2, \dots, b_n, c_n\) 拼接而成的最短字符串成为原字符串的 p 型编码。

e.g. 100200300 可以被表示为 \(1\)\(1\)\(2\)\(0\)\(1\)\(2\)\(2\)\(0\)\(1\)\(3\)\(2\)\(0\)。其 p 型编码为 112012201320

易知,每个数字字符串有固定的 p 型编码,但每个 p 型编码没有固定的数字字符串。

给出一个 p 型编码,请求出这个编码对应的字符串有几个。

Solution

考场思路

一顿乱搞,\(30\) pts。

正解

\(f_i\)\(1 \sim i\) 这段编码对应的字符串的方案数。

则:

\[f_i = \left\{\begin{matrix} 1 & i = 0 \\ 0 & a_{i + 1} = 0 \\ \sum_{j = 1}^{i - 1} f_j & \ a_i \neq a_j \end{matrix}\right. \]

如果直接暴力转移的话,只能得到 \(60\) pts。

注意到,\(f_i\) 其实就是 \(\sum f_j - \sum f_j (a_i \neq a_j)\)。所以只需要在计算的同时计算 \(\sum f\)\(a_i = a_j\) 的情况的和记录下来就好了。

Complexity

时间复杂度:\(O(|a|)\)

Code

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

const int maxn = 1e6 + 5;
const int mod = 998244353;

char s[maxn];
int a[maxn], sum[maxn], f[maxn];

int main()
{
	freopen("hard.in", "r", stdin);
	freopen("hard.out", "w", stdout);
	int x, s2 = 0;
	scanf("%s", s);
	for (x = 1; s[x - 1] != '\0'; x ++)
		a[x] = s[x - 1];	
	int n = x - 1;
	f[0] = 1;
	for (int i = 1; i <= n; i ++)
	{
		if (a[i + 1] != '0')
            f[i] = (s2 - sum[a[i]] + mod) % mod;
		s2 = (s2 + f[i - 1]) % mod;
		sum[a[i - 1]] = (sum[a[i - 1]] + f[i - 1]) % mod;
	}
	cout << f[n];
	return 0;
} 

上为迷惑 \(90\) pts 的 std。

我也不知道为啥 qwq,先这样吧。

T3. 八卦阵

Description

给定一张 \(n\) 个点, \(m\) 条边的有向图。每条边 \(i\) 有一个困难度 \(a_i\)

每个点 \(u\) 有八个状态:\(b_{u_1}, b_{u_2}, \dots, b_{u_8}\),这八个状态为均 \([1,8]\)之间的整数(不一定是排列),在第 \(i\) 秒中,\(u\) 的状态为 \(b_{u_{(i-1) \text{mod} 8 + 1}}\)

对于任意两个状态 \(i,j\) 都存在一个复杂度 \(c_{ij}\)

在第一秒开始时位于一号点,每次他可以用一秒从当前点 \(u\) 走到另一个有边相连的点 \(v\)。也就是说,在第一秒内走过第一条边,在第二秒内走过第二条边…… 在第 \(i\) 秒通过第 \(j\) 条边从点 \(u\) 走到点 \(v\),需要付出 \(a_j + c_{b_{u,(i - 1) \text{mod} 8 + 1},b_{v, (i - 1) \text{mod} 8 + 1}}\) 的代价。 问从点 \(1\) 走到点 \(n\) 最小的代价。

Solution

考场思路

没写。

正解

考虑分层图的思路,建出八个图,每个图的边权代表在 \(i \ \text{mod} \ 8\) 为特定值时的边权。

每条边与下一层图相连,跑最短路就行了。

Complexity

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

Code

略。
posted @ 2023-09-24 15:58  Clyfort  阅读(9)  评论(0编辑  收藏  举报