就是对于一个哞叫,实质是寻找他的第一个数,我称为新树,然后就是寻找这个这个哞叫,假设这个哞叫最后两个数字为啊,a,b,当然,a = b,然后我要寻找a前面的与a不同的数的数量,同时保证每个不同的数只会统计一次,然后在寻找b前面的数的数量,然后求他们两个数的数量的最小值,因为a与b之间的数是不能用作这个哞叫最前面的数的,所以我们现在要找的就是a或者b前面的不同的数的数量。
因为数太大,所以我用了不受数字大小影响的map数组,(我也没想到能用map硬堆出来),然后我的p3是用来标记这个数在前面是否出现过,同时判断她存在几个,这样可以在后序遍历p3时候找到>=2的然后进行判断。
然后重点是p1,p2,我通过两个map数组然后依次标记他前面的新数数量,比如说有四个相同的数,通过p4标记这个数,然后p4通过每次加一,让p1,p2轮流得到这个点在这个坐标下,他的新数大小,最后,因为我们不知道p1,p2哪个存的倒数第二个(当然,例子中可以简单看出来),所以用min来找出最小的。
样例
blablabla
#include <iostream>
#include <unordered_map>
#include <algorithm>
using namespace std;
typedef long long int ll;
const int N = 1e6 + 100;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
ll a[N];
unordered_map<ll, int> p1; // 存放第一个位置
unordered_map<ll, int> p2; // 存放第二个位置
unordered_map<ll, int> p3; // 判断是否是新数
unordered_map<ll, int> p4; // 通过奇偶来决定更新哪个map
ll sum = 0;
int maxn = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
if (p3.find(a[i]) == p3.end()) { // 是新数
sum++;
}
p3[a[i]]++; // 标记是否是新数
if (p4[a[i]] % 2 == 0) { // 是新数或者第二个位置也已经确定,偶数的话更新第一个
p1[a[i]] = sum - 1;
p4[a[i]]++;
} else if (p4[a[i]] % 2 == 1) { // 第一个位置已填满,奇数的话更新第二个
p2[a[i]] = sum - 1;
p4[a[i]]++;
}
}
ll x = 0;
for (auto t : p3) {
if (t.second >= 2) {
x += min(p1[t.first], p2[t.first]);
}
}
cout << x;
return 0;
}
算法1
(暴力枚举) O(n2)
blablabla
时间复杂度
参考文献
C++ 代码
blablabla
算法2
(暴力枚举) O(n2)
blablabla
时间复杂度
参考文献
C++ 代码
blablabla
用unordered_map是减小时间复杂度,如果直接用map的话最后一个例子会tle