Problem

大意就是,给你一个数列,定义某个函数mex(l,r)表示在数列的第l个和第r个之间没有出现过的最小自然数。要求的就是对于这个数列的∑i≤j≤ni,j=1mex(i,j)∑i,j=1i≤j≤nmex(i,j)\sum_{i,j=1}^{i\leq j\leq n}mex(i,j)

hdu链接
Sample Input
3
0 1 3
5
1 0 2 0 1
0
Sample Output
5
24

Solution

法一
注意到mex(i,j)在i相同,j不断增大时满足非严格递增,那么我们可以从小到大枚举j,求解∑ji=1mex(i,j)∑i=1jmex(i,j)\sum_{i=1}^jmex(i,j)。记上次的答案为add,计算与上次答案的差量即可。另外,我们知道在最坏情况下就是n个数占用了0,1,2……此时mex(1,n)为n,也就是说,mex(i,j)≤j−i+1mex(i,j)≤j−i+1mex(i,j)\leq j-i+1,所以当处理a数组时,当ai大于n时就不需要处理了。
法二
出处好像是这
大概就是这样。。用线段树维护mex序列。同样的,由于法一中非严格递增的性质,我们首先求出∑nimex(1,i)∑inmex(1,i)\sum_i^n mex(1,i),那么考虑左端点的改变对答案的影响。我们设ai下次出现位置为j,考虑[i+1,j-1]区间的mex,当mex(i,j)>ai时,那么在我们删去ai后,mex会更新为ai。

Code

法一

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int size=200100;
int n,a[size],pre[size],s[size];
long long ans,add;
template <typename Tp> bool read(Tp &x)
{x=0;char ch=getchar();while((ch<'0'||ch>'9')&&ch!=-1) ch=getchar();if(ch==-1) return false;while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return true;
}
int min(int x,int y){return x<y?x:y;}
int main()
{while(read(n)&&n){for(int i=1;i<=n;i++)read(a[i]);memset(pre,0,sizeof(pre));memset(s,0,sizeof(s));ans=add=0;for(int i=1;i<=n;i++,ans+=add)if(a[i]<=n){int temp=pre[a[i]];pre[a[i]]=i;for(int j=a[i];j<=n;j++){s[j]=(j==0?pre[j]:min(s[j-1],pre[j]));if(s[j]>temp)add+=s[j]-temp;else//s满足非严格递减,break以免TLEbreak;}}printf("%lld\n",ans);}return 0;
}

法二

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int size=200010;
ll ans,sum[size<<2],f[size<<2];
int n,cnt,mx[size<<2],a[size],mex[size];
int head[size],nxt[size];
struct date{int v,p;
}edge[size];
template <typename Tp> bool read(Tp &x)
{x=0;char ch=getchar();while((ch<'0'||ch>'9')&&ch!=-1) ch=getchar();if(ch==-1) return false;while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return true;
}
int max(int x,int y){return x>y?x:y;}
bool cmp(date x,date y)
{if(x.v==y.v)return x.p<y.p;return x.v<y.v;
}
void pushup(int rt)
{sum[rt]=sum[rt<<1]+sum[rt<<1|1];mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void pushdown(int l,int rt)
{if(f[rt]){f[rt<<1]=1;f[rt<<1|1]=1;sum[rt<<1]=mx[rt]*(l-(l>>1));sum[rt<<1|1]=mx[rt]*(l>>1);mx[rt<<1]=mx[rt];mx[rt<<1|1]=mx[rt];f[rt]=0;}
}
void build(int l,int r,int rt)
{f[rt]=0;if(l==r){sum[rt]=mex[l];mx[rt]=mex[l];return;}int mid=(l+r)>>1;build(l,mid,rt<<1);build(mid+1,r,rt<<1|1);pushup(rt);
}
void update(int l,int r,int L,int R,int rt,int c)
{if(L<=l&&r<=R){sum[rt]=1ll*c*(r-l+1);mx[rt]=c;f[rt]=1;return;}pushdown(r-l+1,rt);int mid=(l+r)>>1;if(L<=mid)update(l,mid,L,R,rt<<1,c);if(mid<R)update(mid+1,r,L,R,rt<<1|1,c);pushup(rt);
}
int query(int l,int r,int rt,int c)
{if(l==r)return l;pushdown(r-l+1,rt);int ans,mid=(l+r)>>1;if(mx[rt<<1]>c)ans=query(l,mid,rt<<1,c);elseans=query(mid+1,r,rt<<1|1,c);pushup(rt);return ans;
}
int main()
{int i,j,l;while(read(n)){if(!n)break;cnt=0;memset(head,0,sizeof(head));for(i=1;i<=n;i++)//预处理{read(a[i]);edge[i].v=a[i];edge[i].p=i;for(j=cnt;j<n;j++)if(!head[j])break;cnt=j;if(a[i]==j){for(++j;j<n;j++)if(!head[j])break;mex[i]=j;cnt=j;}else mex[i]=j;if(a[i]<n)head[a[i]]=1;}sort(edge+1,edge+n+1,cmp);edge[n+1].v=-1;for(i=1;i<=n;i++){if(edge[i].v==edge[i+1].v)nxt[edge[i].p]=edge[i+1].p;elsenxt[edge[i].p]=n+1;}build(1,n,1);ans=sum[1];for(i=1;i<=n;i++){update(1,n,i,i,1,0);if(mx[1]>a[i]){l=query(1,n,1,a[i]);if(l<nxt[i])update(1,n,l,nxt[i]-1,1,a[i]);}ans+=sum[1];}printf("%lld\n",ans);}return 0;
}

HDU-4747 Mex相关推荐

  1. hdu 4747 mex 线段树+思维

    http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意: 我们定义mex(l,r)表示一个序列a[l]....a[r]中没有出现过得最小的非负整数, 然后我 ...

  2. HDU 4747 Mex

    4747 思路: 线段树 先求出mex(1,1), mex(1, 2) , mex(1,3),...,mex(1,n)(单调上升),先将这些mex放进线段树里求和 然后再求出next[i]表示下一次出 ...

  3. HDU 4747 Mex【线段树上二分+扫描线】

    [题意概述] 一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和. [题解] 扫描线+线段树. 我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到 ...

  4. HDU - 4747 Mex(线段树)

    题意: 计算    其中mex即为博弈中出现的mex(未出现的最小非负整数). 分析: 有两种方法,递推有点懵(以后再来补QAQ),就写了线段树 想法是每次求以i为起点的区间的mex值的和,最后累加即 ...

  5. HDOJ 4747 Mex

    非常好的线段树题....此题必定会火..... Mex Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K ( ...

  6. 动态规划总结与题目分类

    源博客链接:http://blog.csdn.net/cc_again/article/details/25866971 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少 ...

  7. 『ACM-算法-动态规划』初识DP动态规划算法

    一.多阶段决策过程的最优化问题 在现实生活中,有类活 动的过程,由于 它的特殊性,可将过程分成若干个互相阶段.在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果.当阶段决策的选取不是任意确 ...

  8. (转)dp动态规划分类详解

    dp动态规划分类详解 转自:http://blog.csdn.NET/cc_again/article/details/25866971 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间 ...

  9. 《动态规划》— 动态规划分类

    动态规划(英语:Dynamic programming,DP)是一种在数学.计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法. 动态规划常常适用于有重叠子问题和最 ...

  10. 转:动态规划题目分类

    https://blog.csdn.net/cc_again/article/details/25866971 一.简单基础dp 这类dp主要是一些状态比较容易表示,转移方程比较好想,问题比较基本常见 ...

最新文章

  1. 面试官:你分析过mybatis工作原理吗?
  2. 使用Windows兼容包简化向.NET Core的迁移
  3. 【Android 安装包优化】p7zip 源码交叉编译 Android 平台可执行程序 ( 下载 p7zip 源码 | 交叉编译 Android 中使用 7z 可执行程序 )
  4. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第21篇]CRT算法如何提高RSA的性能?
  5. C语言预处理功能——关于字符串化和符号粘贴
  6. java基础-public/private/protected的具体区别
  7. Adobe illustrator 论文图形编辑和排版 - 连载 1
  8. 大数据和BI商业智能有何区别?有何相关?
  9. linux怎样自制库_苹果开源Swift System,增加Linux支持
  10. python函数参数值_python 函数参数
  11. [渝粤教育] 西南交通大学 工程流体力学 参考 资料
  12. linux宝塔面板是什么,宝塔面板是什么
  13. mysql insert 1062_mysql insert error 1062
  14. 如何让Join跑的更快?(文末送书)
  15. 研究领域、研究课题、研究方向三者的区别
  16. 在docker容器中创建用户组和用户,并且多用户共用一个anaconda环境
  17. Wilcoxon signed-rank test和Wilcoxon rank-sum test及其在SciPy中的使用注意事项
  18. LOAM算法(论文+代码)详解(一)—— 引言+特征提取
  19. 关于ExecuteNonQuery() 方法
  20. Compound 治理——执行队列 TimeLock

热门文章

  1. reg51 reg52区别
  2. 人工智能发展将使人类沦落为“无用阶级”
  3. 计算机物理安全策略,关于计算机信息安全策略的维度思考研究
  4. 自学成才秘籍!机器学习深度学习经典资料汇总
  5. 数据分析【实践】——教育行业指标体系搭建和生命周期维护
  6. 自娱自乐的FreeRTOS——config.h配置文件详解
  7. HTML源码大放送1
  8. c++无法启动程序,系统找不到指定文件的处理方法
  9. mysql bin_mysql-bin是什么文件?
  10. ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用