Luogu P10144 [WC/CTS2024] 水镜 题解
对于任何一段连续上升的区间,我们不需要管它。对于任何一段连续下降的区间,我们只需要用 减去每个数就可以化为一段连续上升的区间。因此,对于这两种区间,我们可以看作一个点。
于是,我们发现其实 只会被波峰 和波谷 限制住。我们考虑对于每个波峰和波谷,是否存在一种方式可以走过去。
对于一个波峰 ,我们有两种方法:
第一种,,这样就得满足 ,即 。
第二种, 且 ,这种情况下显然 。但是这样就得满足 ,即 。
如果 ,则一定存在上述两种方法中的一种可以走过这个波峰。
对于一个波谷 ,我们有两种方法:
第一种, 且 ,这种情况下显然 。这样就得满足 ,即 。
第二种,,这样就得满足 ,即 。这里不需要管对 的影响,因为在下一个波峰中会统计。
如果 ,则一定存在上述两种方法中的一种可以走过这个波谷。
对于波峰套波峰或波峰套波谷一类的情况,这样也是对的。原因是这样的限制给了每个波峰和波谷两种选择方式,套起来的两个波峰或波谷一定有一种方式可以匹配。
最后,我们发现合法的区间可以使用双指针维护。上面的这些限制可以使用 multiset
来维护,支持插入,删除,查询最值。
时间复杂度 ,非常优秀。
#include <bits/stdc++.h>
using namespace std;
long long n,a[600000],ans=0,j=3;
multiset<long long>b,s;
void add(long long x)
{
if(x==n)return;
if(a[x]>=a[x-1]&&a[x]>=a[x+1])s.insert(-a[x]-min(a[x-1],a[x+1]));
if(a[x]<=a[x-1]&&a[x]<=a[x+1])b.insert(a[x]+max(a[x-1],a[x+1]));
}
void del(long long x)
{
if(x==n)return;
if(a[x]>=a[x-1]&&a[x]>=a[x+1])s.erase(s.find(-a[x]-min(a[x-1],a[x+1])));
if(a[x]<=a[x-1]&&a[x]<=a[x+1])b.erase(b.find(a[x]+max(a[x-1],a[x+1])));
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
add(2);
for(int i=1;i<=n;i++)
{
if(i!=1)del(i);
while((b.empty()||s.empty()||*b.begin()>-(*s.begin()))&&j<=n)add(j),j++;
ans+=(j-i);
}
printf("%lld\n",ans-n);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探