2018年NOIP普及组复赛题解

题目涉及算法:

  • 标题统计:字符串入门题;
  • 龙虎斗:数学题;
  • 摆渡车:动态规划;
  • 对称二叉树:搜索。

标题统计

题目链接:https://www.luogu.org/problem/P5015
这道题目是一道基础题,考察你字符(串)的输入。
实现代码如下:

#include <cstdio>

char c;
int cnt;

int main() {
	while (c = getchar()) {
		if (c == EOF || c == '\n') break;
		if (c != ' ') cnt ++;
	}
	printf("%d\n", cnt);
	return 0;
}

龙虎斗

题目链接:https://www.luogu.org/problem/P5016
这道题目是一道简单的数学推理题。
但是它有一些条件是可以化简的,比如“某一刻天降神兵,共有 \(s_1\) 位工兵突然出现在了 \(p_1\) 号兵营”这个条件,你是可以直接处理成一开始这 \(s_1\) 位工兵就出现在 \(p_1\) 位置的。
取出多余条件之后,实现的时候从左到右枚举一下势力和之差即可。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;

int n, m, p1, p2;
long long a[maxn], s1, s2, sum;

int main() {
	cin >> n;
	for (int i = 1; i <= n; i ++) cin >> a[i];
	cin >> m >> p1 >> s1 >> s2;
	a[p1] += s1;
	p2 = 1;
	for (int i = 1; i <= n; i ++)
		sum += ( (long long) (i - m) ) * a[i];
	for (int i = 1; i <= n; i ++)
		if ( abs(sum + (i-m) * s2) < abs(sum + (p2-m) * s2) ) p2 = i;
	cout << p2 << endl;
	return 0;
}

摆渡车

题目链接:
本题涉及算法:动态规划,有一丢丢贪心的思想。
我们令 \(f[i]\) 表示在时刻 \(i\) 发车时所有最晚在时刻 \(i\) 到站的人的最少等待时间,则:
\(f[i]\) 只跟范围在 \((i-2*m, i-m]\)\(f[j]\) 有关,因为对于任意 \(i\) 来说:
\(f[i] \le f[i-m]\) (因为 \(i-m\) 时刻发车,我 \(i\) 又回来了)。
那么我令 \(tmp_{j,i}\) 表示时刻 \(j\) 开始到时刻 \(i\) 到站的人的总等待时长,则:
\(f[i] = \max(f[j]+tmp_{j,i})\) (其中 \(i-2 \times m \lt j \le i-m\) )。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4000400;

int n, m, t, maxt;
long long f[maxn], cnt[maxn];

int main() {
	cin >> n >> m;
	for (int i = 0; i < n; i ++) {
		cin >> t;
		cnt[t] ++;
		if (t > maxt) maxt = t;
	}
	for (int i = 0; i <= maxt + m; i ++) {
		long long tmp = 0;
		for (int j = 0; j < m && i-j >=0; j ++) {
			tmp += cnt[i-j] * ( (long long) j );
		}
		f[i] = tmp;
		if (i >= m) f[i] += f[i-m];
		for (int j = m+1; j <= 2*m && i - j >= 0; j ++) {
			tmp += cnt[i-j+1] * ( (long long) (j-1) );
			if (f[i-j] + tmp <= f[i]) f[i] = f[i-j] + tmp;
		}
	}
	long long ans = f[maxt];
	for (int i = 1; i <= m; i ++) {
		ans = min(ans, f[maxt+i]);
	}
	cout << ans << endl;
	return 0;
}

对称二叉树

题目链接:https://www.luogu.org/problem/P5018
这道题目用搜索竟然过了。
表示这样的话最坏情况下时间复杂度应该有 \(O(n^2)\) 囧、
另说标准解法应该是树hash,有时间了解一下。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4000400;

int n, m, t, maxt;
long long f[maxn], cnt[maxn];

int main() {
	cin >> n >> m;
	for (int i = 0; i < n; i ++) {
		cin >> t;
		cnt[t] ++;
		if (t > maxt) maxt = t;
	}
	for (int i = 0; i <= maxt + m; i ++) {
		long long tmp = 0;
		for (int j = 0; j < m && i-j >=0; j ++) {
			tmp += cnt[i-j] * ( (long long) j );
		}
		f[i] = tmp;
		if (i >= m) f[i] += f[i-m];
		for (int j = m+1; j <= 2*m && i - j >= 0; j ++) {
			tmp += cnt[i-j+1] * ( (long long) (j-1) );
			if (f[i-j] + tmp <= f[i]) f[i] = f[i-j] + tmp;
		}
	}
	long long ans = f[maxt];
	for (int i = 1; i <= m; i ++) {
		ans = min(ans, f[maxt+i]);
	}
	cout << ans << endl;
	return 0;
}
posted @ 2019-11-08 16:29  codedecision  阅读(3481)  评论(0编辑  收藏  举报