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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM