本文涉及知识点
本博文代码打包下载
【C++】树状数组的使用、原理、封装类、样例
逆序对
[USACO17JAN] Balanced Photo G
题面翻译
题目描述
FJ 正在安排他的 N N N 头奶牛站成一排来拍照( 1 ≤ N ≤ 1 0 5 1\le N \le 10^5 1≤N≤105)。序列中的第 i i i 头奶牛的高度是 h i h_i hi,且序列中所有的奶牛的身高都不同。
就像他的所有牛的照片一样,FJ希望这张照片看上去尽可能好。他认为,如果 L i L_i Li 和 R i R_i Ri 的数目相差 1 1 1 倍以上,第 i i i 头奶牛就是不平衡的( L i L_i Li 和 R i R_i Ri 分别代表第 i i i 头奶牛左右两边比她高的奶牛的数量)。也就是说,如果 L i L_i Li 和 R i R_i Ri 中的较大数大于较小数的 2 2 2 倍,第 i i i 头奶牛就是不平衡的。FJ 不希望他有太多的奶牛不平衡。
请帮助 FJ 计算不平衡的奶牛数量。
输入格式
第一行一个整数 N N N。
接下 N N N 行包括 H 1 H_1 H1 到 H n H_n Hn,每行一个不超过 1 0 9 10^9 109 的非负整数。
输出格式
请输出不平衡的奶牛数量。
题目描述
Farmer John is arranging his N N N cows in a line to take a photo ( 1 ≤ N ≤ 100 , 000 1 \leq N \leq 100,000 1≤N≤100,000). The height of the i i ith cow in sequence is h i h_i hi, and the heights of all cows are distinct.
As with all photographs of his cows, FJ wants this one to come out looking as nice as possible. He decides that cow i i i looks “unbalanced” if L i L_i Li and R i R_i Ri differ by more than factor of 2, where L i L_i Li and R i R_i Ri are the number of cows taller than i i i on her left and right, respectively. That is, i i i is unbalanced if the larger of L i L_i Li and R i R_i Ri is strictly more than twice the smaller of these two numbers. FJ is hoping that not too many of his cows are unbalanced.
Please help FJ compute the total number of unbalanced cows.
输入格式
The first line of input contains N N N. The next N N N lines contain h 1 … h N h_1 \ldots h_N h1…hN, each a nonnegative integer at most 1,000,000,000.
输出格式
Please output a count of the number of cows that are unbalanced.
样例 #1
样例输入 #1
7
34
6
23
0
5
99
2
样例输出 #1
3
离散化+树状数组
本题只考虑相对大小,故可以离散化。两轮循环:
第一轮计算:r[i]。
第二轮计算:l[i]。
ans += max(l[i]+r[i]) > 2*min(l[i]+r[i])
代码
核心代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include <bitset>
using namespace std;
template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
in >> pr.first >> pr.second;
return in;
}
template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;
return in;
}
template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
return in;
}
template<class T = int>
vector<T> Read() {
int n;
scanf("%d", &n);
vector<T> ret(n);
for(int i=0;i < n ;i++) {
cin >> ret[i];
}
return ret;
}
template<class T = int>
vector<T> Read(int n) {
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
template<int N = 12 * 1'000'000>
class COutBuff
{
public:
COutBuff() {
m_p = puffer;
}
template<class T>
void write(T x) {
int num[28], sp = 0;
if (x < 0)
*m_p++ = '-', x = -x;
if (!x)
*m_p++ = 48;
while (x)
num[++sp] = x % 10, x /= 10;
while (sp)
*m_p++ = num[sp--] + 48;
}
inline void write(char ch)
{
*m_p++ = ch;
}
inline void ToFile() {
fwrite(puffer, 1, m_p - puffer, stdout);
}
private:
char puffer[N], * m_p;
};
template<int N = 12 * 1'000'000>
class CInBuff
{
public:
inline CInBuff() {
fread(buffer, 1, N, stdin);
}
inline int Read() {
int x(0), f(0);
while (!isdigit(*S))
f |= (*S++ == '-');
while (isdigit(*S))
x = (x << 1) + (x << 3) + (*S++ ^ 48);
return f ? -x : x;
}
private:
char buffer[N], * S = buffer;
};
class CDiscretize //离散化
{
public:
CDiscretize(vector<int> nums)
{
sort(nums.begin(), nums.end());
nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
m_nums = nums;
for (int i = 0; i < nums.size(); i++)
{
m_mValueToIndex[nums[i]] = i;
}
}
int operator[](const int value)const
{
auto it = m_mValueToIndex.find(value);
if (m_mValueToIndex.end() == it)
{
return -1;
}
return it->second;
}
int size()const
{
return m_mValueToIndex.size();
}
vector<int> m_nums;
protected:
unordered_map<int, int> m_mValueToIndex;
};
template<class ELE = int >
class CTreeArr
{
public:
CTreeArr(int iSize) :m_vData(iSize + 1)
{
}
void Add(int index, ELE value)
{
if ((index < 0) || (index >= m_vData.size() - 1)) { return; }
index++;
while (index < m_vData.size())
{
m_vData[index] += value;
index += index & (-index);
}
}
ELE Sum(int index)//[0...index]之和
{
index++;
ELE ret = 0;
while (index)
{
ret += m_vData[index];
index -= index & (-index);
}
return ret;
}
ELE Sum() { return Sum(m_vData.size() - 2); }
ELE Get(int index)
{
return Sum(index) - Sum(index - 1);
}
private:
vector<ELE> m_vData;
};
class Solution {
public:
int Ans(vector<int> h) {
const int N = h.size();
CDiscretize dis(h);
for (auto& i : h) {
i = dis[i] + 1;
}
const int M = *max_element(h.begin(), h.end());
vector<int> rs(N);
{
CTreeArr<int> tree(M + 1);
for (int i = N - 1; i >= 0; i--) {
rs[i] = N - (i + 1) - tree.Sum(h[i]);
tree.Add(h[i], 1);
}
}
int ans = 0;
{
CTreeArr<int> tree(M + 1);
for (int i = 0; i < N; i++) {
const int left = i - tree.Sum(h[i]);
ans += max(left, rs[i]) > 2 * min(left, rs[i]);
tree.Add(h[i], 1);
}
}
return ans;
}
};
int main() {
#ifdef _DEBUG
freopen("a.in", "r", stdin);
#endif // DEBUG
auto a = Read<int>();
auto res = Solution().Ans(a);
cout << res << endl;
#ifdef _DEBUG
/*Out(a, ",a=");
printf("k=%d", k);
*/
#endif // DEBUG
return 0;
}
单元测试
vector<int> h;
TEST_METHOD(TestMethod11)
{
h = { 34,6,23,0,5,99,2 };
auto res = Solution().Ans(h);
AssertEx(3, res);
}
扩展阅读
我想对大家说的话 |
---|
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步优快云学院,听白银讲师(也就是鄙人)的讲解。
https://edu.youkuaiyun.com/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.youkuaiyun.com/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。