题目链接:

acm.hdu.edu.cn/showproblem.php?pid=4747

Mex

Time Limit: 15000/5000 MS (Java/Others)
Memory Limit: 65535/65535 K (Java/Others)

问题描述

Mex is a function on a set of integers, which is universally used for impartial game theorem. For a non-negative integer set S, mex(S) is defined as the least non-negative integer which is not appeared in S. Now our problem is about mex function on a sequence.

Consider a sequence of non-negative integers {ai}, we define mex(L,R) as the least non-negative integer which is not appeared in the continuous subsequence from aL to aR, inclusive. Now we want to calculate the sum of mex(L,R) for all 1 <= L <= R <= n.

输入

The input contains at most 20 test cases.

For each test case, the first line contains one integer n, denoting the length of sequence.

The next line contains n non-integers separated by space, denoting the sequence.

(1 <= n <= 200000, 0 <= ai <= 10^9)

The input ends with n = 0.

输出

For each test case, output one line containing a integer denoting the answer.

样例输入

3

0 1 3

5

1 0 2 0 1

0

样例输出

5

24

Hint

For the first test case:

mex(1,1)=1, mex(1,2)=2, mex(1,3)=2, mex(2,2)=0, mex(2,3)=0,mex(3,3)=0.

1 + 2 + 2 + 0 +0 +0 = 5.

题意

mex(s)表示没有在集合s中出现的最小非负数,现在要求所有的mex(si)(si为由数列的一个子串组成的集合)的和。

题解

1、递推、 [参考]

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII; const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0); //start---------------------------------------------------------------------- const int maxn=2e5+10; int n;
int arr[maxn];
//last[x]表示x这个数最晚出现的位置
//full[x]表示完全覆盖0到x的且左边界最靠右的区间
int last[maxn],full[maxn];
//dp[i]表示以i结尾的所有区间的贡献
LL dp[maxn]; void init(){
clr(dp,0);
clr(full,0);
clr(last,0);
} int main() {
while(scf("%d",&n)==1&&n){
init();
for(int i=1;i<=n;i++) scf("%d",&arr[i]);
LL ans=0;
for(int i=1;i<=n;i++){
dp[i]=dp[i-1];
if(arr[i]<n){
int v=arr[i];
int pre=last[v];
last[v]=i;
for(int j=v;j<n;j++){
if(j) full[j]=min(last[j],full[j-1]);
else full[j]=i;
if(full[j]>pre) dp[i]+=full[j]-pre;
else break;
}
}
ans+=dp[i];
}
prf("%lld\n",ans);
}
return 0;
} //end-----------------------------------------------------------------------

2、线段树

初始时线段树上第i个节点存mex(a[1]~a[i])(注意!这个存在单调性!)。

然后我们依次从a[1]开始删除,直到删到a[n-1]。 如果删掉a[1],那么我们对于原本mex值就小于等于a[1]的节点自然没有影响,而对于mex>a[1]且其它位置不存在a[1]的元素,删掉这个a[1]之后它的mex值就会等于a[1],所以我们只要用线段树update一下区间[第一个mex值大于a[1](根据单调性在线段树上二分查找)的位置,下一个值等于a[1]的位置-1]。

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII; const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0); //start---------------------------------------------------------------------- const int maxn=2e5+10; LL sumv[maxn<<2];
int mexv[maxn<<2],setv[maxn<<2];
int arr[maxn],b[maxn];
bool vis[maxn];
int mp[maxn],last[maxn];
int n; void pushdown(int o,int l,int r) {
if(setv[o]>=0) {
sumv[lson]=(mid-l+1)*setv[o];
mexv[lson]=setv[o]; sumv[rson]=(r-mid)*setv[o];
mexv[rson]=setv[o]; setv[lson]=setv[rson]=setv[o];
setv[o]=-1;
}
} void maintain(int o) {
sumv[o]=sumv[lson]+sumv[rson];
mexv[o]=max(mexv[lson],mexv[rson]);
} void build(int o,int l,int r) {
if(l==r) {
sumv[o]=mexv[o]=b[l];
} else {
build(lson,l,mid);
build(rson,mid+1,r);
maintain(o);
}
} int _v,_pos;
void query(int o,int l,int r) {
if(l==r) {
if(_v>=mexv[o]) _pos=n+1;
else _pos=l;
} else {
pushdown(o,l,r);
if(_v>=mexv[lson]) query(rson,mid+1,r);
else query(lson,l,mid);
maintain(o);
}
} int ql,qr,_v2;
void update(int o,int l,int r) {
if(ql<=l&&r<=qr) {
sumv[o]=(r-l+1)*_v2;
mexv[o]=_v2;
setv[o]=_v2;
} else {
pushdown(o,l,r);
if(ql<=mid) update(lson,l,mid);
if(qr>mid) update(rson,mid+1,r);
maintain(o);
}
} void init() {
clr(vis,0);
clr(setv,-1);
for(int i=0; i<=n; i++) mp[i]=last[i]=n+1;
} int main() {
while(scf("%d",&n)==1&&n) {
init();
int mex=0;
for(int i=1; i<=n; i++) {
int x;
scf("%d",&x);
arr[i]=x;
if(x<n) vis[x]=1;
while(vis[mex]) mex++;
b[i]=mex;
} for(int i=n; i>=1; i--) {
if(arr[i]<n) {
mp[i]=last[arr[i]]-1;
last[arr[i]]=i;
}
} // for(int i=1;i<=n;i++) prf("%d ",b[i]); puts("");
build(1,1,n); LL ans=sumv[1];
// bug(ans);
for(int i=1; i<n; i++) { if(arr[i]>=n) {
ans+=sumv[1];
} else {
_v=arr[i];
query(1,1,n);
// prf("%d,%d\n",_pos,mp[i]); if(_pos<=mp[i]){
ql=_pos,qr=mp[i];
_v2=arr[i];
update(1,1,n);
}
ans+=sumv[1];
}
// bug(ans);
} prf("%lld\n",ans);
}
return 0;
} //end-----------------------------------------------------------------------

Notes

枚举区间: dp[i]表示以i为右边界的所有区间的贡献。

HDU 4747 Mex 递推/线段树的更多相关文章

  1. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  2. HDU.5692 Snacks ( DFS序 线段树维护最大值 )

    HDU.5692 Snacks ( DFS序 线段树维护最大值 ) 题意分析 给出一颗树,节点标号为0-n,每个节点有一定权值,并且规定0号为根节点.有两种操作:操作一为询问,给出一个节点x,求从0号 ...

  3. HDU.1556 Color the ball (线段树 区间更新 单点查询)

    HDU.1556 Color the ball (线段树 区间更新 单点查询) 题意分析 注意一下pushdown 和 pushup 模板类的题还真不能自己套啊,手写一遍才行 代码总览 #includ ...

  4. HDU.1166 敌兵布阵 (线段树 单点更新 区间查询)

    HDU.1166 敌兵布阵 (线段树 单点更新 区间查询) 题意分析 加深理解,重写一遍 代码总览 #include <bits/stdc++.h> #define nmax 100000 ...

  5. HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对)

    HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对) 题意分析 给出n个数的序列,a1,a2,a3--an,ai∈[0,n-1],求环序列中逆序对 ...

  6. HDU.1689 Just a Hook (线段树 区间替换 区间总和)

    HDU.1689 Just a Hook (线段树 区间替换 区间总和) 题意分析 一开始叶子节点均为1,操作为将[L,R]区间全部替换成C,求总区间[1,N]和 线段树维护区间和 . 建树的时候初始 ...

  7. hdu 1754 I Hate It 线段树 点改动

    // hdu 1754 I Hate It 线段树 点改动 // // 不多说,裸的点改动 // // 继续练 #include <algorithm> #include <bits ...

  8. hdu 1166 敌兵布阵 线段树 点更新

    // hdu 1166 敌兵布阵 线段树 点更新 // // 这道题裸的线段树的点更新,直接写就能够了 // // 一直以来想要进线段树的坑,结果一直没有跳进去,今天算是跳进去吧, // 尽管十分简单 ...

  9. R - Weak Pair HDU - 5877 离散化+权值线段树+dfs序 区间种类数

    R - Weak Pair HDU - 5877 离散化+权值线段树 这个题目的初步想法,首先用dfs序建一颗树,然后判断对于每一个节点进行遍历,判断他的子节点和他相乘是不是小于等于k, 这么暴力的算 ...

随机推荐

  1. ruby中的循环——times

    times:能够得知循环的次数 格式: 循环次数.times do 希望循环的处理 end 或者可省略do~end,用{~}代替: 循环次数.times{ 希望循环的处理 } 循环从第0次开始,可以看 ...

  2. 基于visual studio 2017 以及cubemx 搭建stm32的开发环境(0)

    (1)安装visual studio 2017 官网下载安装即可 (2)安装visual GDB 链接:https://pan.baidu.com/s/1TgXI1BRQLAWiWlqCcIS9TA ...

  3. spark 例子groupByKey分组计算

    spark 例子groupByKey分组计算 例子描述: [分组.计算] 主要为两部分,将同类的数据分组归纳到一起,并将分组后的数据进行简单数学计算. 难点在于怎么去理解groupBy和groupBy ...

  4. (数据科学学习手札54)Python中retry的简单用法

    一.简介 retry是一个用于错误处理的模块,功能类似try-except,但更加快捷方便,本文就将简单地介绍一下retry的基本用法. 二.基本用法 retry: 作为装饰器进行使用,不传入参数时功 ...

  5. 基于R实现k-means法与k-medoids法

    k-means法与k-medoids法都是基于距离判别的聚类算法.本文将使用iris数据集,在R语言中实现k-means算法与k-medoids算法. k-means聚类 首先删去iris中的Spec ...

  6. Titanic幸存预测分析(Kaggle)

    分享一篇kaggle入门级案例,泰坦尼克号幸存遇难分析. 参考文章: 技术世界,原文链接 http://www.jasongj.com/ml/classification/ 案例分析内容: 通过训练集 ...

  7. 数据结构与算法之排序(3)插入排序 ——in dart

    插入排序的思想比冒泡.选择要复杂,效率也比前两者更高.插入排序算法中运用了分治.逆向冒泡等思想,假设i之前的都是排好序的,i之后的都是待比较并排序的,然后逐次逆向向前比较,若小于前值,则将前值循环依次 ...

  8. 20155315实验三 敏捷开发与XP实践

    实验内容 1.XP基础 2.XP核心实践 3.相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程: 2.完成实验.撰 ...

  9. P3368 【模板】树状数组 2(区间增减,单点查询)

    P3368 [模板]树状数组 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表 ...

  10. C++ OI图论 学习笔记(初步完结)

    矩阵图 使用矩阵图来存储有向图和无向图的信息,用无穷大表示两点之间不连通,用两点之间的距离来表示连通.无向图的矩阵图是关于主对角线对称的. 如图所示: 使用dfs和bfs对矩阵图进行遍历 多源最短路径 ...