ABC371E I Hate Sigma Problems 题解

ABC371E I Hate Sigma Problems 题解

  • 题目描述
    • 问题陈述
    • 限制因素
  • 样例1解析
  • 题解
    • (1) 暴力枚举
      • 做法
      • 代码
      • 运行结果
    • (2) 暴力优化
      • 做法
      • 代码
      • 运行结果
    • 正解
      • 代码
      • 运行结果
  • 结语

题目描述

问题陈述

给你一个长度为 N N N 的整数序列 A = ( A 1 , A 2 , … , A N ) A = (A_1, A_2, \ldots, A_N) A=(A1,A2,,AN) 。定义 f ( l , r ) f(l, r) f(l,r) 为:

  • 子序列 ( A l , A l + 1 , … , A r ) (A_l, A_{l+1}, \ldots, A_r) (Al,Al+1,,Ar) 中不同值的个数。

计算下面的表达式

∑ i = 1 N ∑ j = i N f ( i , j ) \displaystyle \sum_{i=1}^{N}\sum_{j=i}^N f(i,j) i=1Nj=iNf(i,j)

限制因素

  • 1 ≤ N ≤ 2 × 1 0 5 1\leq N\leq 2\times 10^5 1N2×105
  • 1 ≤ A i ≤ N 1\leq A_i\leq N 1AiN
  • 所有输入值均为整数。

样例1解析

f ( 1 , 1 ) = ( A 1 ) 中不同值的个数 = ( 1 ) 中不同值的个数 = 1 f(1, 1) = (A_1) 中不同值的个数 = (1) 中不同值的个数 = 1 f(1,1)=(A1)中不同值的个数=(1)中不同值的个数=1
f ( 1 , 2 ) = ( A 1 , A 2 ) 中不同值的个数 = ( 1 , 2 ) 中不同值的个数 = 2 f(1, 2) = (A_1, A_2) 中不同值的个数 = (1, 2) 中不同值的个数 = 2 f(1,2)=(A1,A2)中不同值的个数=(1,2)中不同值的个数=2
f ( 1 , 3 ) = ( A 1 , A 2 , A 3 ) 中不同值的个数 = ( 1 , 2 , 2 ) 中不同值的个数 = 2 f(1, 3) = (A_1, A_2, A_3) 中不同值的个数 = (1, 2, 2) 中不同值的个数 = 2 f(1,3)=(A1,A2,A3)中不同值的个数=(1,2,2)中不同值的个数=2
f ( 2 , 2 ) = ( A 2 ) 中不同值的个数 = ( 2 ) 中不同值的个数 = 1 f(2, 2) = (A_2) 中不同值的个数 = (2) 中不同值的个数 = 1 f(2,2)=(A2)中不同值的个数=(2)中不同值的个数=1
f ( 2 , 3 ) = ( A 2 , A 3 ) 中不同值的个数 = ( 2 , 2 ) 中不同值的个数 = 1 f(2, 3) = (A_2, A_3) 中不同值的个数 = (2, 2) 中不同值的个数 = 1 f(2,3)=(A2,A3)中不同值的个数=(2,2)中不同值的个数=1
f ( 3 , 3 ) = ( A 3 ) 中不同值的个数 = ( 3 ) 中不同值的个数 = 1 f(3, 3) = (A_3) 中不同值的个数 = (3) 中不同值的个数 = 1 f(3,3)=(A3)中不同值的个数=(3)中不同值的个数=1
∑ i = 1 3 ∑ j = i 3 f ( i , j ) \ \ \ \ \displaystyle \sum_{i = 1}^{3} \sum_{j = i}^{3} f(i, j)     i=13j=i3f(i,j)
= f ( 1 , 1 ) + f ( 1 , 2 ) + f ( 1 , 3 ) + f ( 2 , 2 ) + f ( 2 , 3 ) + f ( 3 , 3 ) = f(1, 1) + f(1, 2) + f(1, 3) + f(2, 2) + f(2, 3) + f(3, 3) =f(1,1)+f(1,2)+f(1,3)+f(2,2)+f(2,3)+f(3,3)
= 1 + 2 + 2 + 1 + 1 + 1 = 1 + 2 + 2 + 1 + 1 + 1 =1+2+2+1+1+1
= 8 = 8 =8

题解

(1) 暴力枚举

做法

按照题目要求,枚举 i i i j j j,然后算一下从 i i i j j j 的不同值的个数。
算不同值的个数时,可以用一个数组记录每个值是否在之前出现过,每遍历一个数,如果它之前没出现过,就把答案 + 1 + 1 +1,否则直接跳过。时间复杂度 O ( n 3 ) O(n^3) O(n3)

代码

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;typedef long long LL;const int N = 200010;int n;
int a[N];
bool st[N];
LL ans;void work(int l, int r)
{int res = 0;for (int i = 1; i <= n; i ++ ) st[i] = false;for (int i = l; i <= r; i ++ ){if (!st[a[i]]) res ++ ;st[a[i]] = true;}ans += res;
}int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);for (int i = 1; i <= n; i ++ )for (int j = i; j <= n; j ++ )work(i, j);printf("%lld\n", ans);return 0;
}

运行结果

在这里插入图片描述

(2) 暴力优化

做法

我们发现,每次我们都把整个 s t st st 数组清空,因此浪费了很多时间。我们可以在每次 i + 1 i + 1 i+1 时清空 s t st st 数组,当 j j j 循环时,每次将 A j A_j Aj 加入 s t st st,然后当前的 r e s res res 就是 f ( i , j ) f(i, j) f(i,j)。时间复杂度 O ( n 2 ) O(n^2) O(n2)

代码

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;typedef long long LL;const int N = 200010;int n;
int a[N];
bool st[N];
LL ans;void work(int l, int r)
{int res = 0;for (int i = 1; i <= n; i ++ ) st[i] = false;for (int i = l; i <= r; i ++ ){if (!st[a[i]]) res ++ ;st[a[i]] = true;ans += res;}
}int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);for (int i = 1; i <= n; i ++ )work(i, n);printf("%lld\n", ans);return 0;
}

运行结果

在这里插入图片描述

正解

刚才,我们优化了 j j j,现在我们考虑优化 i i i,即求出一个 ∑ j = 1 n f ( 1 , j ) \displaystyle \sum_{j = 1}^n f(1, j) j=1nf(1,j),就能推出 ∑ j = i n f ( i , j ) ( 2 ≤ i ≤ n ) \displaystyle \sum_{j = i}^{n} f(i, j) (2 \le i \le n) j=inf(i,j)(2in)

我们考虑一下,如果 i i i 变成了 i + 1 i + 1 i+1,那么 f ( i , j ) f(i, j) f(i,j) 变成 f ( i + 1 , j ) f(i + 1, j) f(i+1,j) 有什么变化。
显然,如果 A i A_i Ai i i i ~ j j j 中只出现一次,那么 i i i ~ j j j A i A_i Ai 这个数出现次数为 1 1 1,而 i + 1 i + 1 i+1 ~ j j j A i A_i Ai 这个数出现次数为 0 0 0,其它数出现次数不变,相当于只有 A i A_i Ai 从有到没有,不同值个数 − 1 - 1 1。如果 A i A_i Ai i i i ~ j j j 中出现一次以上,那么 i i i ~ j j j A i A_i Ai 这个数出现次数 > 1 > 1 >1,而 i + 1 i + 1 i+1 ~ j j j A i A_i Ai 这个数出现次数为 ≥ 1 \ge 1 1,其它数出现次数不变,相当于所有数的存现都没有变,不同值个数不变。

接着,我们发现存在一个 k k k,使得 j j j i i i k k k 个数发生变化, j j j k + 1 k + 1 k+1 n n n 个数不发生变化。因为每次 j + 1 j + 1 j+1 时每个数的个数都只会增加,所以 A i A_i Ai 的出现次数是单调不减的,所以一但 A i > 1 A_i > 1 Ai>1 将一直 A i > 1 A_i > 1 Ai>1,所以 k k k 存在。

最后,我们发现,如果 A i A_i Ai 后面还有 = A i = A_i =Ai 的数,那么 k k k 等于第一个 = A i = A_i =Ai 的下标 − 1 - 1 1,否则 k = n k = n k=n。因为如果 A i A_i Ai 后面还有 = A i = A_i =Ai 的数,那么当 j j j 到第一个 = A i = A_i =Ai 的下标时, A i A_i Ai 的数量最先 > 1 > 1 >1 因此 k k k 等于第一个 = A i = A_i =Ai 的下标 − 1 - 1 1。如果 A i A_i Ai 后面没有 = A i = A_i =Ai 的数,那么无论如何 A i A_i Ai 的出现次数都 = 1 = 1 =1,所以永远不可能存在两个值为 A i A_i Ai 的数,所以 k = n k = n k=n

因此,我们预处理出 i = 1 i = 1 i=1 ∑ j = 1 n f ( i , j ) \displaystyle \sum_{j = 1}^n f(i, j) j=1nf(i,j) 的结果和每个数后面第一个与它相同的下标(如果没有则设为 n n n)。接着, i i i 1 1 1 n − 1 n - 1 n1 遍历,每次算出依次去掉 A i A_i Ai后会把 $ \sum_{j = 1}^n f(i, j)$ 减去的数 = k − i + 1 k - i + 1 ki+1。最后把预处理的数和每一次去掉剩下的数加在一起就是答案。

时间复杂度 O ( n ) O(n) O(n)

代码

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;typedef long long LL;const int N = 200010;int n;
int a[N];
bool st[N];
int ne[N], last[N];int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);LL sum = 0, cnt = 0;for (int i = 1; i <= n; i ++ ){if (!st[a[i]]){st[a[i]] = true;cnt ++ ;}sum += cnt;ne[last[a[i]]] = i;last[a[i]] = i;}LL ans = sum;for (int i = 1; i < n; i ++ ){int t = ne[i];if (!t) t = n + 1;sum -= t - i;ans += sum;}printf("%lld\n", ans);return 0;
}

运行结果

在这里插入图片描述

结语

再去看这道题,我们先从暴力开始,一步一步优化,最终成功解决了题目。
巧妙的做法往往不是一蹴而就的,而是一步一步优化得到的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1537095.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

PyCharm 安装教程

传送门 PyCharm 是一款由 JetBrains 开发的强大的 Python 集成开发环境&#xff08;IDE&#xff09;。它支持多种功能&#xff0c;包括调试、代码补全、智能代码分析、版本控制集成等&#xff0c;特别适合开发 Python 项目。接下来&#xff0c;我们将详细介绍如何在不同操作系…

每日一个数据结构-跳表

文章目录 什么是跳表&#xff1f;示意图跳表的基本原理跳表的操作跳表与其他数据结构的比较 跳表构造过程 什么是跳表&#xff1f; 跳表&#xff08;Skip List&#xff09;是一种随机化的数据结构&#xff0c;它通过在有序链表上增加多级索引来实现快速查找、插入和删除操作。…

<<编码>> 第 12 章 二进制加法器--16位加法器 示例电路

16 位加法器内部结构 info::操作说明 鼠标单击逻辑输入切换 0|1 状态 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/code-hlchs-examples/assets/circuit/code-hlchs-ch12-10-16-bit-adder-internal.txt 16 位加法器示例 info:…

详解JUC

Java并发工具包&#xff08;Java Util Concurrent&#xff0c; 简称JUC&#xff09;是Java提供的一组用于简化多线程编程的类和接口&#xff0c;它包含了用于线程同步、并发数据结构、线程池、锁、原子操作以及其他并发实用工具的丰富集合。 1. 线程池 线程池是 Java 并发编程…

SOMEIP_ETS_112: SD_Empty_Option

测试目的&#xff1a; 验证DUT能够拒绝长度为0的IPv4选项的SubscribeEventgroup消息&#xff0c;并以SubscribeEventgroupNAck作为响应。 描述 本测试用例旨在确保DUT遵循SOME/IP协议&#xff0c;当接收到一个IPv4选项长度为0的SubscribeEventgroup消息时&#xff0c;能够正…

电子竞技信息交流平台|基于java的电子竞技信息交流平台系统小程序(源码+数据库+文档)

电子竞技信息交流平台系统小程序 目录 基于java的电子竞技信息交流平台系统小程序 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设…

如何设置 Django 错误邮件通知 ?

Django 是一个强大的 web 框架&#xff0c;非常适合那些想要完美快速完成任务的人。它有许多内置的工具和特性&#xff0c;一个有用的特性是 Django 可以在出现错误时发送电子邮件提醒。这对开发人员和管理员非常有用&#xff0c;因为如果出现问题&#xff0c;他们会立即得到通…

基于Springboot的物流管理系统设计与实现(附源代码)

物流管理|物流管理系统|基于Springboot的物流管理系统设计与实现 物流管理系统源码&#xff1a;物流管理系统主要是借助计算机&#xff0c;通过对物流管理系统所需的信息管理&#xff0c;物流管理系统的目的 2.2物流管理系统作用 2.3物流管理系统的发展趋势 3物流管理系统分析…

课堂助手|微信课堂助手系统小程序(源码+数据库+文档)

课堂助手|课堂助手系统小程序 目录 微信课堂助手系统小程序 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c;阿…

react 组件通讯

组件通讯 组件是独立且封闭的单元&#xff0c;默认情况下&#xff0c;只能使用组件自己的数据。在组件化过程中&#xff0c;我们将一个完整的功能拆分成多个组件&#xff0c;以更好的完成整个应用的功能。而在这个过程中&#xff0c;多个组件之间不可避免的要共享某些数据。为…

【蓝牙协议栈】精讲蓝牙PCM和URAT

前言 在蓝牙通信中&#xff0c;PCM和UART是两种不同的数据传输接口&#xff0c;用于连接蓝牙模块和其他设备。它们的作用和特点如下&#xff1a; 1. PCM&#xff08;Pulse Code Modulation&#xff09; PCM&#xff1a;(pulse coded modulation)脉冲编码调制&#xff0c;是将…

Hybrid接口的基础配置

Hybrid模式是交换机端口的一种配置模式&#xff0c;它允许端口同时携带多个VLAN&#xff08;虚拟局域网&#xff09;的流量。Hybrid端口可以指定哪些VLAN的数据帧被打上标签&#xff08;tagged&#xff09;和哪些VLAN的数据帧在发送时去除标签&#xff08;untagged&#xff09;…

MySQL_数据类型简介

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…

QT学习与数据库连接

1.基础 1. 安装最后一个非在线版本 5.14, 没有的话联系我 新建一个.cpp文件 #include <QApplication> #include <QLabel> #include <QLineEdit> #include <QPushButton> #include <QHBoxLayout> #include <QVBoxLayout> #include <Q…

道路横幅检测数据集 2000张 街道横幅 带标注 voc yolo

项目背景&#xff1a; 城市中的街道横幅通常用于广告宣传、公共通知等目的&#xff0c;但在某些情况下&#xff0c;它们也可能影响交通安全或市容市貌。因此&#xff0c;对街道横幅进行自动化检测不仅可以帮助城市管理机构及时发现并处理不当悬挂的横幅&#xff0c;还可以辅助…

滑坡落石检测数据集

滑坡落石检测数据集 1500张 滑坡落石 带标注 voc yolo 项目背景&#xff1a; 滑坡落石是地质灾害中的一种常见现象&#xff0c;它对人类生活和基础设施构成了严重威胁。及时准确地检测滑坡落石对于预防灾害发生、减少损失至关重要。传统的检测方法往往依赖于人工巡查&#xff…

【Python】高效图像处理库:pyvips

月亮慢慢变圆&#xff0c;日子慢慢变甜。 在图像处理领域&#xff0c;pyvips 是一个轻量级且高效的库&#xff0c;适合处理大规模图像、实现高性能的操作。相较于其他常见的图像处理库如 PIL 或 OpenCV&#xff0c;pyvips 以其低内存占用和出色的速度脱颖而出。本文将介绍 pyv…

第312题|二重积分求旋转体体积(二)|武忠祥老师每日一题

解题思路&#xff1a;先画出图像&#xff0c;再利用旋转体体积计算公式进行解题。 1. 旋转体体积计算公式&#xff1a; 2.点到直线计算公式&#xff1a; 有了上面两条知识储备之后我们开始计算。 第一步&#xff1a;先计算出点到直线的距离&#xff1a; ymx&#xff0c;y-mx…

清理Go/Rust编译时产生的缓存

Go Mac 1T的磁盘频频空间高级&#xff0c;发现是/Users/yourname/Library/Caches/go-build 目录占用了大量空间。 此目录保存来自 Go 构建系统的缓存构建工件。 如果目录太大&#xff0c;请运行go clean -cache。 运行go clean -fuzzcache以删除模糊缓存。 当时直接手工清理了…

【UE5 C++课程系列笔记】01——Visual Studio环境安装

1. 进入Visual Studio 官网&#xff0c;点击下载 下载社区版即可 下载后点击应用程序开始安装 2. 在“工作负荷”中&#xff0c;勾选如下选项 在“单个组件”中&#xff0c;勾选如下选项&#xff1a; 3. 等待下载安装 4. 安装好后&#xff0c;点击“继续但无需代码” 选择“工具…