当前位置: 首页 > news >正文

【单调栈 离散化】P10798 「CZOI-R1」消除威胁|普及+

本文涉及的基础知识点

C++单调栈

P10798 「CZOI-R1」消除威胁

题目背景

本题数据已修复。

题目描述

给定一个序列 {An}\{A_n\}{An}

我们称序列 AAA 中的一个区间 [l,r][l,r][l,r] 具有威胁,当且仅当 1≤l<r≤n1\le l<r\le n1l<rnAl=ArA_l=A_rAl=Ar,且 ∀i∈[l,r]\forall i\in[l,r]i[l,r] 满足 ∣Ai∣≤∣Al∣|A_i|\le|A_l|AiAl

你可以操作 AAA 任意次,每次操作选择一个 AiA_iAi 修改为 −Ai-A_iAi。请问最后序列 AAA 中具有威胁的不同区间最少有多少个?

两个区间 [l1,r1][l_1,r_1][l1,r1][l2,r2][l_2,r_2][l2,r2] 不同,当且仅当 l1≠l2l_1 \ne l_2l1=l2r1≠r2r_1 \ne r_2r1=r2

输入格式

第一行一个整数 nnn ,表示 AAA 的长度。

第二行 nnn 个整数,表示 {An}\{A_n\}{An}

输出格式

第一行一个正整数,表示最少的具有威胁的区间个数。

输入输出样例 #1

输入 #1

8
3 2 1 2 3 -1 3 3

输出 #1

2

说明/提示

【数据范围】

本题采用捆绑测试

  • Subtask #1(10pts10\text{ pts}10 pts):n≤10n\le10n10
  • Subtask #2(10pts10\text{ pts}10 pts):n≤103n\le10^3n103
  • Subtask #3(10pts10\text{ pts}10 pts):∣Ai∣≤60|A_i|\le60Ai60
  • Subtask #4(10pts10\text{ pts}10 pts):∣Ai∣|A_i|Ai 均相等。
  • Subtask #5(20pts20\text{ pts}20 pts):n≤105n\le10^5n105
  • Subtask #6(40pts40\text{ pts}40 pts):无特殊限制。

对于 100%100\%100% 的数据,1≤n≤5×1051\le n\le5\times10^51n5×105∣Ai∣≤109|A_i|\le10^9Ai109

单调栈+离散化

由于只关心绝对值是否相等,故可对绝对值离散化。
minx[x] 记录所有绝对值为x的下标。
性质一:任意A[i] > x,则不会存在威胁区间[l,r],A[l]==x,l<i<r。故下标i,将minx[x]拆分成两段。
性质二:某段有cnt个元素,如果值全部相等,则威胁区间最多f(cnt)=cnt×(cnt−1)÷2f(cnt)=cnt \times (cnt-1)\div 2f(cnt)=cnt×(cnt1)÷2。一半为负,一半为正,威胁区间最少:f(cnt/2)+f(cnt-cnt/2)。如果这些元素的值为0,则无法一半正数,一半负数。
注意:离散化时,确保0被离散成0,非0不会离散成0。

求最大值

方法一用倍增(ST表)。方案二单调栈vMax[i]==j,表示A[0∼i−10\sim i-10i1]中,A[j] > A[i],且j最大。如果不存在,j为-1。
将minx[x]当栈,从栈顶开始处理。
如果minx[inxs[i]] > inxs[i-1],处理 inxs[i ∼\sim 未处理]

代码

核心代码

#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 T1, class T2, class T3, class T4, class T5 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4, T5>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t);return in;
}template<class T1, class T2, class T3, class T4, class T5, class T6 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4, T5, T6>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t) >> get<4>(t) >> get<5>(t);return in;
}template<class T = int>
vector<T> Read() {int n;cin >> n;vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}
template<class T = int>
vector<T> ReadNotNum() {vector<T> ret;T tmp;while (cin >> tmp) {ret.emplace_back(tmp);if ('\n' == cin.get()) { break; }}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 = 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;AuotToFile();}void writestr(const char* sz) {strcpy(m_p, sz);m_p += strlen(sz);AuotToFile();}inline void write(char ch){*m_p++ = ch;AuotToFile();}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);m_p = puffer;}~COutBuff() {ToFile();}
private:inline void AuotToFile() {if (m_p - puffer > N - 100) {ToFile();}}char  puffer[N], * m_p;
};template<int N = 1'000'000>
class CInBuff
{
public:inline CInBuff() {}inline CInBuff<N>& operator>>(char& ch) {FileToBuf();ch = *S++;return *this;}inline CInBuff<N>& operator>>(int& val) {FileToBuf();int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行		return *this;}inline CInBuff& operator>>(long long& val) {FileToBuf();long long x(0); int f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);val = f ? -x : x; S++;//忽略空格换行return *this;}template<class T1, class T2>inline CInBuff& operator>>(pair<T1, T2>& val) {*this >> val.first >> val.second;return *this;}template<class T1, class T2, class T3>inline CInBuff& operator>>(tuple<T1, T2, T3>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val);return *this;}template<class T1, class T2, class T3, class T4>inline CInBuff& operator>>(tuple<T1, T2, T3, T4>& val) {*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);return *this;}template<class T = int>inline CInBuff& operator>>(vector<T>& val) {int n;*this >> n;val.resize(n);for (int i = 0; i < n; i++) {*this >> val[i];}return *this;}template<class T = int>vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {*this >> ret[i];}return ret;}template<class T = int>vector<T> Read() {vector<T> ret;*this >> ret;return ret;}
private:inline void FileToBuf() {const int canRead = m_iWritePos - (S - buffer);if (canRead >= 100) { return; }if (m_bFinish) { return; }for (int i = 0; i < canRead; i++){buffer[i] = S[i];//memcpy出错			}m_iWritePos = canRead;buffer[m_iWritePos] = 0;S = buffer;int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);if (readCnt <= 0) { m_bFinish = true; return; }m_iWritePos += readCnt;buffer[m_iWritePos] = 0;S = buffer;}int m_iWritePos = 0; bool m_bFinish = false;char buffer[N + 10], * S = buffer;
};template<class T = int>
class CDiscretize //离散化
{
public:CDiscretize(vector<T> 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 T 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<T> m_nums;
protected:unordered_map<T, int> m_mValueToIndex;
};
class Solution {public:long long Ans(vector<int>& A) {const int N = A.size();int M = 0;{vector<int> tmp = { 0 };for (const auto& i : A) { tmp.emplace_back(abs(i)); }CDiscretize<int> dis(tmp);for (auto& i : A) {//A[i]全部改成正数if (i >= 0) {i = dis[i];}else {i = dis[-i];}}M = dis.size();}vector<int> vMax(N, -1);{stack<int> sta;for (int i = 0;i < N;i++) {while (sta.size() && (A[sta.top()] <= A[i])) {sta.pop();}if (sta.size()) {vMax[i] = sta.top();}sta.emplace(i);}					}vector<stack<int>> minx(M);for (int i = 0;i < N;i++) {minx[abs(A[i])].emplace(i);}auto F = [&](long long x) {return x * (x - 1) / 2;};auto G = [&](long long x, bool b0) {if (b0) { return F(x); }return F(x / 2) + F(x - x / 2);};long long ans=0;				int val = -1;for (auto& sta: minx) {val++;int cnt = 0;while (sta.size()) {const int left = vMax[sta.top()];sta.pop();cnt++;if (sta.size() && (left >= sta.top())) {ans += G(cnt, 0 == val);cnt = 0;}}ans += G(cnt, 0 == val);}return ans;}};int main() {ios::sync_with_stdio(0);cin.tie(nullptr);cout.tie(nullptr);
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG		auto A = Read<int>();
#ifdef _DEBUG		//printf("W=%d,", W);Out(A, "A=");//Out(abcd, "abcd=");
#endif // DEBUG	auto res = Solution().Ans(A);cout << res << "\r\n";return 0;
}

代码

核心代码

	long long CheckAns(vector<int>& A) {const int N = A.size();long long ans = 0;for (int i = 0;i < N;i++) {for (int j = i + 1; j < N;j++) {if (A[i] != A[j]) { continue; }bool b = true;for (int k = i + 1; k < j;k++) {if (abs(A[k]) > abs(A[i])) { b = false; }}ans += b;}}return ans;}void Check(vector<int>& A) {const int N = A.size();assert(N <= 15);long long ans = LLONG_MAX / 2;for (int m = 0;m < (1 << N);m++) {for (int i = 0;i < N;i++) {int sign = ((1 << i) & m) ? 1 : -1;A[i] = abs(A[i]) * sign;}auto cur =CheckAns(A);ans = min(ans, cur);}auto res = Solution().Ans(A);AssertEx(ans, res);}vector< int > A;TEST_METHOD(TestMethod01){A = { 3,2,1,2,3,-1,3,3 };auto res = Solution().Ans(A);AssertEx(2LL, res);}TEST_METHOD(TestMethod02){A = { 0,0,0};auto res = Solution().Ans(A);AssertEx(3LL, res);}TEST_METHOD(TestMethod03){A = { 0,0,0,1,0,0 };auto res = Solution().Ans(A);AssertEx(4LL, res);}TEST_METHOD(TestMethod04){A = { 1,1,1 };auto res = Solution().Ans(A);AssertEx(1LL, res);}TEST_METHOD(TestMethod05){srand(time(nullptr));A.assign(10, 0);for (int k = 0;k < 100 ;k++){for (int i = 0;i < 10;i++) {A[i] = rand() % 5;}Check(A);}}TEST_METHOD(TestMethod06){A.assign(400000, 1);auto res = Solution().Ans(A);AssertEx(199999 * 100000LL*2, res);}TEST_METHOD(TestMethod07){A = { 1,-2,1 };auto res = Solution().Ans(A);AssertEx(0LL, res);}TEST_METHOD(TestMethod08){A = { 1,-2,1,-3,1 };auto res = Solution().Ans(A);AssertEx(0LL, res);}TEST_METHOD(TestMethod10){A = { 3,-4,3,1,1,2,1,1,2,2,1,2,3 };Check(A);}

单元测试

	long long CheckAns(vector<int>& A) {const int N = A.size();long long ans = 0;for (int i = 0;i < N;i++) {for (int j = i + 1; j < N;j++) {if (A[i] != A[j]) { continue; }bool b = true;for (int k = i + 1; k < j;k++) {if (abs(A[k]) > abs(A[i])) { b = false; }}ans += b;}}return ans;}void Check(vector<int>& A) {const int N = A.size();assert(N <= 15);long long ans = LLONG_MAX / 2;for (int m = 0;m < (1 << N);m++) {for (int i = 0;i < N;i++) {int sign = ((1 << i) & m) ? 1 : -1;A[i] = abs(A[i]) * sign;}auto cur =CheckAns(A);ans = min(ans, cur);}auto res = Solution().Ans(A);AssertEx(ans, res);}vector< int > A;TEST_METHOD(TestMethod01){A = { 3,2,1,2,3,-1,3,3 };auto res = Solution().Ans(A);AssertEx(2LL, res);}TEST_METHOD(TestMethod02){A = { 0,0,0};auto res = Solution().Ans(A);AssertEx(3LL, res);}TEST_METHOD(TestMethod03){A = { 0,0,0,1,0,0 };auto res = Solution().Ans(A);AssertEx(4LL, res);}TEST_METHOD(TestMethod04){A = { 1,1,1 };auto res = Solution().Ans(A);AssertEx(1LL, res);}TEST_METHOD(TestMethod05){srand(time(nullptr));A.assign(10, 0);for (int k = 0;k < 100 ;k++){for (int i = 0;i < 10;i++) {A[i] = rand() % 5;}Check(A);}}TEST_METHOD(TestMethod06){A.assign(400000, 1);auto res = Solution().Ans(A);AssertEx(199999 * 100000LL*2, res);}TEST_METHOD(TestMethod07){A = { 1,-2,1 };auto res = Solution().Ans(A);AssertEx(0LL, res);}TEST_METHOD(TestMethod08){A = { 1,-2,1,-3,1 };auto res = Solution().Ans(A);AssertEx(0LL, res);}TEST_METHOD(TestMethod10){A = { 3,-4,3,1,1,2,1,1,2,2,1,2,3 };Check(A);}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
员工说:技术至上,老板不信;投资人的代表说:技术至上,老板会信。
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

http://www.dtcms.com/a/500230.html

相关文章:

  • 邵武建设局网站wordpress多用户博客
  • (Kotlin高级特性三)Kotlin密封类(Sealed Class)在何时比枚举更适用?
  • kalibr进行相机内参以及相机imu的融合标定
  • 最简单的做网站工具网站发外链的好处
  • 北京神州网站建设xxx网站策划书
  • linux开启bbr网络优化
  • 前后端路径处理完整指南:从零开始理解Web开发中的路径问题
  • 为什么网站要备案头条新闻 免费下载
  • 汇通网做期货的网站做期货的网站软件开发平台 devcloud
  • 专门做橱柜衣柜效果图的网站青海网站建设怎么建设
  • 算法沉淀第六天(牛客小白月赛122 和 Codeforces Round 1059 (Div. 3))
  • 网站建设与维护蒋勇从前端开发培训机构有哪些
  • 网站建设后的心得浙江省建设通网站
  • Git的多人协作
  • 成都开发网站建设怎么下载应用商店
  • 14-哈希SHA1案例:宝钢
  • Python数据分析:小实例,数人头
  • 单页面网站怎么做软件项目开发文档模板
  • 松岗营销型网站建设软文范例大全
  • 本地网站建设方案信息大全网站数据迁移教程
  • 麦肯锡:从「AI价值悖论」到代理式 AI 的产业化落地
  • 金华市建设技工学校教育培训网站什么是网站建设整体策划方案
  • C++动态规划入门指南——助力CSP竞赛夺冠(加强版)
  • 【前端高级特效】使用 CSS 实现毛玻璃模糊背景效果(含完整源码讲解)
  • 网站备案花钱么培训学校网站
  • 【人工智能系列:机器学习学习和进阶01】机器学习初学者指南:理解核心算法与应用
  • 利用舵机实现机器人行走
  • 做网站时需要FTP工具吗济南市工程造价信息网
  • 电商网站的特点wordpress投稿者发附件
  • CSDN:打造专业的技术名片