P9572 题解
思路
这题中的第一问我们只要看 中有几个数是在 中出现过即可,因为 可以无限扩大,这意味着 中出现过的数的个数也可以无限扩大,这样 中的在 中出现过的数肯定都可以到最长公共子序列中去。
对于第二问,我们可以想到用贪心的思路去解决。所谓贪心,就是能不让 变大就不变大。对于贪心,我们要做到以下两点:
- 能不让 变大就不变大;
- 在做到第 点的同时,我们要让这个位置在 中尽可能靠前。
而让这个位置在 中尽可能靠前,那可以把这个元素的所有位置都存在一个 STL_vector 里,并进行二分查找。二分查找也不用手写,有个叫 upper_bound 的库函数,它可以找到一个区间内第 个比 大的元素的地址,如果仍不理解,请看代码注释。
代码
# 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;
}

浙公网安备 33010602011771号