P9572 题解

题目传送门

思路

这题中的第一问我们只要看 TT 中有几个数是在 SS 中出现过即可,因为 kk 可以无限扩大,这意味着 SS 中出现过的数的个数也可以无限扩大,这样 TT 中的在 SS 中出现过的数肯定都可以到最长公共子序列中去。

对于第二问,我们可以想到用贪心的思路去解决。所谓贪心,就是能不让 kk 变大就不变大。对于贪心,我们要做到以下两点:

  1. 能不让 kk 变大就不变大;
  2. 在做到第 11 点的同时,我们要让这个位置在 SS 中尽可能靠前。

而让这个位置在 SS 中尽可能靠前,那可以把这个元素的所有位置都存在一个 STL_vector 里,并进行二分查找。二分查找也不用手写,有个叫 upper_bound 的库函数,它可以找到一个区间内第 11 个比 xx 大的元素的地址,如果仍不理解,请看代码注释。

代码

# include <bits/stdc++.h>
using namespace std;
int n, m, c1, c2, tot, last = 1919810, ans1, ans2, a[1000005], x;
vector <int> v[1000005]; //vector 可以动态调整空间!
int main () {
	cin >> n >> m >> c1 >> c2;
	if (! c1 && ! c2) { //如果你想写正解,这个 if 没啥用
		cout << "0 0";
		return 0;
	}
	for (int i = 0; i < n; ++ i)
		cin >> a[i], v[a[i]].push_back (i);
	while (m --) {
		cin >> x;
		if (v[x].empty ()) //在 S 中没有这个元素,说明不能被选到最长公共子序列中
			continue ;
		++ ans1; //统计第一问的答案
		if (v[x][v[x].size () - 1] <= last) //在这之后没有了,说明要新开一次数组
			++ ans2, last = v[x][0];
		else
			last = v[x][upper_bound (v[x].begin (), v[x].end (), last) - v[x].begin ()]; //在上一个之后的第 1 个比 last 大的元素位置
	}
	cout << c1 * ans1 << ' ' << c2 * ans2;
	return 0;
}
posted @ 2023-08-19 20:00  Vitamin_B  阅读(8)  评论(0)    收藏  举报  来源