题面

CF1418G Three Occurrences

给一个 \(n\) 个数的序列 \(a_i\),求每个出现过的数出现次数为 \(3\) 的子序列个数。

数据范围:\(1\le n\le 5\cdot 10^5\),\(1\le a_i\le n\)。


蒟蒻语

做了半个上午做出了最离谱的做法:表格打叉叉。

用线段树求矩阵面积并实现,时间复杂度 \(\Theta(n\log n)\),总用时 \(1.40 min\)。


蒟蒻解

想象有一个 \(n\times n\) 的表格,行表示右端点,列表示左端点。

如果表格上的数为 \(1\) 表示这个区间没被叉掉,对答案有贡献,否则这个区间不符合题目要求。

可以发现每次叉的都是一个矩阵,线段树扫描线求矩阵面积并即可。

考虑数据:

8
1 1 2 1 2 1 2 1 answer=2

现在的表表是:

\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)

\((1)\) 把左端点大于右端点的给叉了:

\(1\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(1\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(0\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)

\((2)\) 把超过 \(3\) 个相同的数的区间叉了:

\(1\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(1\) \(0\) \(0\) \(0\) \(0\)
\(1\) \(1\) \(1\) \(1\) \(1\) \(0\) \(0\) \(0\)
\(0\) \(1\) \(1\) \(1\) \(1\) \(1\) \(0\) \(0\)
\(0\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\) \(0\)
\(0\) \(0\) \(1\) \(1\) \(1\) \(1\) \(1\) \(1\)

\((3)\) 把少于 \(3\) 个相同的数的区间叉了:

\(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(0\) \(1\) \(0\) \(0\) \(0\) \(0\) \(0\) \(0\)
\(0\) \(0\) \(1\) \(0\) \(0\) \(0\) \(0\) \(0\)

然后剩下的 \(2\) 就是答案了。

手玩一下就可以发现叉的规律了,非常简单易懂,蒟蒻就不负责任地放代码里了。


代码

#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair((a),(b))
#define x first
#define y second
#define be(a) (a).begin()
#define en(a) (a).end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
#define R(i,a,b) for(int i=(a),I=(b);i<I;i++)
#define L(i,a,b) for(int i=(b)-1,I=(a)-1;i>I;i--)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f; //Data
const int N=5e5;
int n,a[N],d[N]; ll ans;
vector<int> id[N];
struct line{
int l,r,t; line(){}
line(int l,int r,int t):l(l),r(r),t(t){}
};
vector<line> p[N+1];
void addmat(int xl,int xr,int yl,int yr){
// cout<<"(["<<xl<<","<<xr<<"),["<<yl<<","<<yr<<"))\n";
p[xl].pb(line(yl,yr,1)),p[xr].pb(line(yl,yr,-1));
} //SegmentTree
const int tN=N<<2;
#define mid ((l+r)>>1)
int mn[tN],mc[tN],mk[tN];
void pushup(int k){
if(mn[k*2+1]<mn[k*2+2]) mn[k]=mn[k*2+1],mc[k]=mc[k*2+1];
else if(mn[k*2+1]>mn[k*2+2]) mn[k]=mn[k*2+2],mc[k]=mc[k*2+2];
else mn[k]=mn[k*2+1],mc[k]=mc[k*2+1]+mc[k*2+2];
}
void pushadd(int k,int v){mn[k]+=v,mk[k]+=v;}
void pushdown(int k){pushadd(k*2+1,mk[k]),pushadd(k*2+2,mk[k]),mk[k]=0;}
void build(int k=0,int l=0,int r=n){
if(r-l==1) return mn[k]=0,mc[k]=1,void();
build(k*2+1,l,mid),build(k*2+2,mid,r),pushup(k);
}
void add(int x,int y,int v,int k=0,int l=0,int r=n){
if(r<=x||y<=l) return; if(x<=l&&r<=y) return pushadd(k,v);
pushdown(k),add(x,y,v,k*2+1,l,mid),add(x,y,v,k*2+2,mid,r),pushup(k);
} //Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
R(i,0,n) id[i].pb(-1),id[i].pb(-1),id[i].pb(-1);
R(i,0,n) cin>>a[i],--a[i],d[i]=sz(id[a[i]]),id[a[i]].pb(i);
R(i,0,n) id[i].pb(n),id[i].pb(n),id[i].pb(n);
// cout<<"ok 60\n";
R(i,0,n){
addmat(i,i+1,i+1,n); // 把左端点大于右端点的给叉了
addmat(i,n,0,id[a[i]][d[i]-3]+1); //把超过 3 个相同的数的区间叉了
addmat(i,id[a[i]][d[i]+2],id[a[i]][d[i]-1]+1,i+1); //把少于 3 个相同的数的区间叉了
}
// cout<<"ok 66\n";
build();
R(i,0,n){ //求个矩阵面积并
for(line u:p[i])if(u.r>u.l) add(u.l,u.r,u.t);
ans+=mc[0]*(mn[0]==0);
}
cout<<ans<<'\n';
return 0;
}

祝大家学习愉快!

题解-CF1418G Three Occurrences的更多相关文章

  1. CF1418G Three Occurrences

    统计满足某些性质的区间个数. 我们考虑移动 \(r\) 指针. 然后考虑把不能选的区间 \(ban\)掉. 具体看下细节吧. #include<iostream> #include< ...

  2. 【字符串】【hash】【倍增】洛谷 P3502 [POI2010]CHO-Hamsters 题解

        这是一道字符串建模+图论的问题. 题目描述 Byteasar breeds hamsters. Each hamster has a unique name, consisting of lo ...

  3. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  4. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  5. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  6. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  7. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  8. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  9. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

随机推荐

  1. golang 简单工厂模式

    package kit //golang简单工厂模式 //go 语言没有构造函数一说,所以一般会定义NewXXX函数来初始化相关类. NewXXX 函数返回接口时就是简单工厂模式,也就是说Golang ...

  2. TCP协议原理与格式初探

    目录 可靠数据传输原理 停等传输下的情况 1.经过完全可靠信道的可靠数据传输 2.经具有比特差错信道的可靠数据传输 3.经具有比特差错的丢包信道的可靠数据传输 流水线传输 1.回退N步(Go-Back ...

  3. zabbix实现自定义自动发现的流程

    前言 本章介绍如何去自定义一个zabbix自动发现的整个流程 过程 首先需要在模板当中创建一个自动发现的规则,这个地方只需要一个名称和一个键值,例如 名称:Ceph Cluster Pool Disc ...

  4. Ceph Bluestore首测

    Bluestore 作为 Ceph Jewel 版本推出的一个重大的更新,提供了一种之前没有的存储形式,一直以来ceph的存储方式一直是以filestore的方式存储的,也就是对象是以文件方式存储在o ...

  5. pytorch框架对RTX 2080Ti RTX 3090的支持与性能测试

    时间点:202011-18 一.背景 2020年9月nvidia发布了30系列的显卡.比起20系列网上的评价是:性能翻倍,价格减半. 最近正好本人手上有RTX 2080Ti 和 RTX 3090,所以 ...

  6. 新鲜出炉!两万月薪的Java工程师面试题,看看你能做出来多少?

    接口和抽象类的区别 接口. 一个类实现了多个接口,那么必须实现接口中所有的抽象方法,如果方法相同,那么只需要Override一次. 所有接口中的默认方法也可以被继承,但是如果两个接口有重名的默认方法, ...

  7. 记录一次tomcat问题排查记录:org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19

    最近项目升级jdk,从jdk7 升级到 jdk8,本地已经自测完成了,需要部署到测试环境,测试环境已经装好 jdk8 了,但是tomcat 的版本还是 7.不过,据我之前了解,tomcat7是可以运行 ...

  8. MySQL的两种日志类型,redo log,binlog

    文章内容学习:极客时间-林晓彬老师-MySQL实战45讲 整理而得 我们知道MySQL数据库在发生意外宕机的情况下,可以将数据恢复到历史的某个时间点,能实现这个功能依靠的是日志,MySQL提供两种类型 ...

  9. Prometheus+Grafana+Alertmanager实现告警推送教程 ----- 图文详解

    前言 本文主要介绍的是Prometheus采集数据,通过Grafana加上PromQL语句实现数据可视化以及通过Alertmanage实现告警推送功能.温馨提示,本篇文章特长,2w多的文字加上几十张图 ...

  10. CentOS升级参考

    CentOS生产系统升级策略: 1)升级前评估 a)确认kernel或包bug. b)用评估工具 c) 测试验证 2)确认升级内容 a)单独升级kernel b)单独升级包 c)都升级 4)确认升级方 ...