Atcoder Beginner Contest 385(补题)

Atcoder Beginner Contest 385

C - Illuminate Buildings(DP)

问题陈述

\(N\) 幢楼房等间距排成一行。第 \(i\) 幢楼房从正面看的高度是 \(H_i\)

你想给其中一些建筑物装上灯饰,以满足以下两个条件:

  • 所选建筑物的高度相同。
  • 所选建筑物的排列间隔相等。

您最多可以选择多少座建筑物?如果您选择的建筑物只有一幢,则认为它满足条件。

输入

输入内容由标准输入法提供,格式如下

\(N\)
\(H_1\) \(\ldots\) \(H_N\)

输出

打印答案。

思路

一般最优性问题都可以考虑一下dp是否可做,这道题刚好是dp。

状态定义:\(f{i,j}\)表示以i栋建筑物结尾,间隔为j的,最多可以选择的建筑物数量.

状态转移:f(i, j) = max(f(i, j), f(i-1, j) + 1) (1 <= j <= i) H(i) = H(i-j)

初始条件:f(i, j)初始值都为1

评述

思考方向有误,明明想了一下dp但是有去找其他方法。代码不是自己写的,找到题解,懒得写。

代码

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

int main() {
	int N;
	cin >> N;
	std::vector<int> H(N);
	for (int i = 0; i < N; i ++)
		cin >> H[i];

	std::vector<vector<int>> dp(N, vector<int>(N + 1));
	for (int i = 0; i < N; i ++) {
		for (int j = 1; j <= N; j ++) dp[i][j] = 1;
		for (int j = 1; j <= i; j ++)
			if (H[i - j] == H[i])
				dp[i][j] = max(dp[i][j], dp[i - j][j] + 1);
	}

	int res = 0;
	for (int i = 0; i < N; i ++) res = max(res, *max_element(dp[i].begin(), dp[i].end()));

	cout << res << endl;
}

Santa Claus 2(差分+二分+优化)

问题陈述

在二维平面上的点 \((X_1,Y_1),\ldots,(X_N,Y_N)\) 上有 \(N\) 座房子。

最初,圣诞老人位于点 \((S_x,S_y)\) 。他将按照 \((D_1,C_1),\ldots,(D_M,C_M)\) 序列进行如下操作:

  • 对于 \(i=1,2,\ldots,M\) 的顺序,他的移动如下:
    • 假设 \((x,y)\) 是他目前所在的点。
      • 如果 \(D_i\) 是 "U",则从 \((x,y)\) 直线移动到 \((x,y+C_i)\)
      • 如果 \(D_i\) 是 "D",则从 \((x,y)\) 直线移动到 \((x,y-C_i)\)
      • 如果 \(D_i\) 是 "L",则从 \((x,y)\) 直线移动到 \((x-C_i,y)\)
      • 如果 \(D_i\) 为 "R",则从 \((x,y)\) 沿直线移动到 \((x+C_i,y)\)

找出他完成所有行动后所在的点,以及他在行动过程中经过或到达的不同房子的数量。如果多次经过同一房屋,则只计算一次。

限制因素

  • \(1 \leq N \leq 2\times 10^5\)
  • \(1 \leq M \leq 2\times 10^5\)
  • \(-10^9 \leq X_i,Y_i \leq 10^9\)
  • 成对的 \((X_i,Y_i)\) 是不同的。
  • \(-10^9 \leq S_x,S_y \leq 10^9\)
  • \((S_x,S_y)\) 没有房子。
  • 每个 \(D_i\) 都是 "U"、"D"、"L"、"R "中的一个。
  • \(1 \leq C_i \leq 10^9\)
  • 所有输入的数字都是整数。

Input

The input is given from Standard Input in the following format:

\(N\) \(M\) \(S_x\) \(S_y\)
\(X_1\) \(Y_1\)
\(\vdots\)
\(X_N\) \(Y_N\)
\(D_1\) \(C_1\)
\(\vdots\)
\(D_M\) \(C_M\)

输出

\((X,Y)\) 为他完成所有操作后所处的点, \(C\) 为经过或到达的不同房子的数量。按此顺序打印 \(X,Y,C\) 并用空格分隔。

思路

题目本身的逻辑不难,但是写起来比较麻烦,而且非常考查优化能力。

我们只需要维护出每一条纵轴和每一条横轴上点的信息和线段的信息,然后统计答案即可

以纵轴为例,枚举每一条纵轴,将这条纵轴上的点排序,在枚举这条纵轴上的线段,用二分查找的方式找到在线段上的点的范围,用差分的方式记录,最后求前缀和得到在线段上的点。枚举横轴时同理。

最后统计答案即可。

评述

麻烦麻烦麻烦麻烦

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

signed main() {
	int N, M, Sx, Sy;
	cin >> N >> M >> Sx >> Sy;

	std::vector<int> X(N), Y(N);
	// SX(i):在i这条纵轴上点的集合
	// SY(i):在i这条横轴上点的集合
	map<int, vector<pair<int, int>>> SX, SY;
	for (int i = 0; i < N; i ++) {
		cin >> X[i] >> Y[i];
		SX[X[i]].push_back({Y[i], i});
		SY[Y[i]].push_back({X[i], i});
	}

	// x(i):在i这条纵轴上的线段集合
	// y(i):在i这条横轴上的线段集合
	map<int, vector<pair<int, int>>> x, y;
	for (int i = 0; i < M; i ++) {
		char op;
		int d;
		cin >> op >> d;

		if (op == 'L') {
			Sx -= d;
			y[Sy].push_back({Sx, Sx + d});
		} else if (op == 'R') {
			Sx += d;
			y[Sy].push_back({Sx - d, Sx});
		} else  if (op == 'U') {
			Sy += d;
			x[Sx].push_back({Sy - d, Sy});
		} else {
			Sy -= d;
			x[Sx].push_back({Sy, Sy + d});
		}
	}

    //标记每一个房子是否满足题意
	std::vector<int> res(N);
	//考查每一条纵轴
	for (auto i : x) { // i.first:表示第i条纵轴,i.second:表示第i条纵轴上的线段集合
		sort(SX[i.first].begin(), SX[i.first].end());
		std::vector<int> ok(SX[i.first].size() + 1);
		for (auto j : i.second) { //j:表示第i.first条纵轴上的每一条线段
			// 用二分的方式查找哪些点在j这条线段上
			int L = lower_bound(SX[i.first].begin(), SX[i.first].end(), make_pair(j.first, 0ll)) - SX[i.first].begin();
			int R = upper_bound(SX[i.first].begin(), SX[i.first].end(), make_pair(j.second, (long long)1E18)) - SX[i.first].begin() - 1;
			ok[L] ++, ok[R + 1] --;
		}
		for (int j = 1; j < SX[i.first].size(); j ++) ok[j] += ok[j - 1];
		for (int j = 0; j < SX[i.first].size(); j ++)
			if (ok[j]) res[SX[i.first][j].second] = 1;
	}
	//考查每一条横轴
	for (auto i : y) {
		sort(SY[i.first].begin(), SY[i.first].end());
		std::vector<int> ok(SY[i.first].size() + 1);
		for (auto j : i.second) {
			int L = lower_bound(SY[i.first].begin(), SY[i.first].end(), make_pair(j.first, 0ll)) - SY[i.first].begin();
			int R = upper_bound(SY[i.first].begin(), SY[i.first].end(), make_pair(j.second, (long long)1E18)) - SY[i.first].begin() - 1;
			ok[L] ++, ok[R + 1] --;
		}
		for (int j = 1; j < SY[i.first].size(); j ++) ok[j] += ok[j - 1];
		for (int j = 0; j < SY[i.first].size(); j ++)
			if (ok[j]) res[SY[i.first][j].second] = 1;
	}

	cout << Sx << ' ' << Sy << ' ' << accumulate(res.begin(), res.end(), 0) << endl;

}
posted @ 2024-12-23 11:02  califeee  阅读(71)  评论(0)    收藏  举报