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

设我们输入的数组为 a[],我们需要从 1 到 n 遍历, 假设遍历到 i 时, 遍历的过程中用b[j]表示从 i 到 j 没出现的最小自然数

先从 n 到 1 扫一遍求出从 1 到各个点的b[j]值

然后遍历a[] 实际上就是不断的把当前a[i] 去掉,比如说去掉a[3]时,剩下的b[4]---b[n] 就表示从4到其他后续点形成的区间中没出现的最小自然数

要知道从 i 到 n ,b[]的值始终是单调递增的

我们每去掉当前a[i]会对b[]数组产生影响,

设下一个和a[i]相等的数出现的位置是 r 那么去掉a[i] 对 r 以及 r 以后的b[] 没有影响

在 i 和 r 之间受影响的段b[]是大于等于a[i]的那一段 假设是(l,r), 这个段内的b[]都大于等于a[i]

去掉a[i]的影响就是这个段内的b[] 都要等于 a[i]

找到r可以事先标记,找 l 和更新段 (l,r) 有两种方法

1,二分找到 l ,然后遍历更新段 (l,r)    这样代码比较短,也比较易懂,但比较耗时,不过可以过

2,线段树维护                                这样代码量会比较大,不过耗时少,线段树的解法应该比较标准

两种代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<string>
  5. #include<cstring>
  6. #include<cmath>
  7. #include<set>
  8. #include<vector>
  9. #include<list>
  10. #include<stack>
  11. #include<queue>
  12. #include<map>
  13.  
  14. using namespace std;
  15.  
  16. typedef long long ll;
  17. typedef pair<int,int> pp;
  18.  
  19. const int INF=0x3f3f3f3f;
  20.  
  21. const int N=200002;
  22. bool exist[N];
  23. int a[N],next[N],f[N];
  24. int b[N];
  25. int bsh(int l,int r,int k)
  26. {
  27. while(l<=r)
  28. {
  29. int mid=(l+r)>>1;
  30. if(b[mid]<=k) l=mid+1;
  31. else r=mid-1;
  32. }
  33. return r;
  34. }
  35. int main()
  36. {
  37. //freopen("data.in","r",stdin);
  38. int n;
  39. while(scanf("%d",&n)!=EOF)
  40. {
  41. if(n==0) break;
  42. for(int i=1;i<=n;++i)
  43. scanf("%d",&a[i]);
  44. for(int i=0;i<=n;++i)
  45. f[i]=n+1;
  46. for(int i=n;i>=1;--i)
  47. if(a[i]<n)
  48. {
  49. next[i]=f[a[i]];
  50. f[a[i]]=i;
  51. }
  52. ll ans=0;
  53. memset(exist,false,sizeof(exist));
  54. ll tmp=0;int l=0;
  55. for(int i=1;i<=n;++i)
  56. {
  57. if(a[i]<n)
  58. {
  59. exist[a[i]]=true;
  60. while(exist[l]) ++l;
  61. }
  62. b[i]=l;
  63. tmp+=b[i];
  64. }
  65. ans=tmp;
  66. for(int i=1;i<n;++i)
  67. {
  68. if(a[i]<n)
  69. {
  70. int r=next[i];
  71. int l=bsh(i,r-1,a[i]);
  72. for(int j=l+1;j<r;++j)
  73. {
  74. tmp-=(b[j]-a[i]);
  75. b[j]=a[i];
  76. }
  77. }
  78. tmp-=b[i];
  79. ans+=tmp;
  80. }
  81. cout<<ans<<endl;
  82. }
  83. return 0;
  84. }
  85.  
  86. #include<iostream>
  87. #include<cstdio>
  88. #include<algorithm>
  89. #include<string>
  90. #include<cstring>
  91. #include<cmath>
  92. #include<set>
  93. #include<vector>
  94. #include<list>
  95. #include<stack>
  96. #include<queue>
  97. #include<map>
  98.  
  99. using namespace std;
  100.  
  101. typedef long long ll;
  102. typedef pair<int,int> pp;
  103.  
  104. const int INF=0x3f3f3f3f;
  105.  
  106. const int N=200002;
  107. bool exist[N];
  108. int a[N],next[N],f[N];
  109. int b[N];
  110. struct node
  111. {
  112. int l,r,k,least;
  113. ll sum;
  114. }tr[N*4];
  115. void build(int x,int l,int r)
  116. {
  117. tr[x].l=l;tr[x].r=r;tr[x].k=-1;
  118. if(l==r)
  119. {
  120. tr[x].least=b[l];
  121. tr[x].sum=b[l];
  122. return ;
  123. }
  124. int mid=(l+r)>>1;
  125. build((x<<1),l,mid);
  126. build((x<<1)|1,mid+1,r);
  127. tr[x].least=min(tr[x<<1].least,tr[(x<<1)|1].least);
  128. tr[x].sum=(tr[x<<1].sum+tr[(x<<1)|1].sum);
  129. }
  130. void update(int x,int l,int r,int k)
  131. {
  132. if(l>r) return ;
  133. if(tr[x].l==l&&tr[x].r==r)
  134. {
  135. tr[x].least=k;
  136. tr[x].k=k;
  137. tr[x].sum=(ll)k*(tr[x].r-tr[x].l+1);
  138. return ;
  139. }
  140. if(tr[x].k!=-1)
  141. {
  142. tr[x<<1].k=tr[x].k;tr[x<<1].least=tr[x<<1].k;
  143. tr[x<<1].sum=(ll)tr[x<<1].k*(tr[x<<1].r-tr[x<<1].l+1);
  144. tr[(x<<1)|1].k=tr[x].k;tr[(x<<1)|1].least=tr[(x<<1)|1].k;
  145. tr[(x<<1)|1].sum=(ll)tr[(x<<1)|1].k*(tr[(x<<1)|1].r-tr[(x<<1)|1].l+1);
  146. tr[x].k=-1;
  147. }
  148. int mid=(tr[x].l+tr[x].r)>>1;
  149. if(r<=mid)
  150. update(x<<1,l,r,k);
  151. else if(l>mid)
  152. update((x<<1)|1,l,r,k);
  153. else
  154. {
  155. update(x<<1,l,mid,k);
  156. update((x<<1)|1,mid+1,r,k);
  157. }
  158. tr[x].least=min(tr[x<<1].least,tr[(x<<1)|1].least);
  159. tr[x].sum=(tr[x<<1].sum+tr[(x<<1)|1].sum);
  160. tr[x].k=-1;
  161. }
  162. int get(int x,int l,int r,int w)
  163. {
  164. if(tr[x].l==tr[x].r)
  165. {
  166. if(tr[x].least>w)
  167. return (l-1);
  168. return l;
  169. }
  170. if(tr[x].k!=-1)
  171. {
  172. tr[x<<1].k=tr[x].k;tr[x<<1].least=tr[x<<1].k;
  173. tr[x<<1].sum=(ll)tr[x<<1].k*(tr[x<<1].r-tr[x<<1].l+1);
  174. tr[(x<<1)|1].k=tr[x].k;tr[(x<<1)|1].least=tr[(x<<1)|1].k;
  175. tr[(x<<1)|1].sum=(ll)tr[(x<<1)|1].k*(tr[(x<<1)|1].r-tr[(x<<1)|1].l+1);
  176. tr[x].k=-1;
  177. }
  178. int mid=(tr[x].l+tr[x].r)>>1;
  179. if(r<=mid)
  180. return get(x<<1,l,r,w);
  181. else if(l>mid)
  182. return get((x<<1)|1,l,r,w);
  183. else
  184. {
  185. if(tr[(x<<1)|1].least<=w)
  186. return get((x<<1)|1,mid+1,r,w);
  187. else
  188. return get(x<<1,l,mid,w);
  189. }
  190. }
  191. ll gsum(int x,int l,int r)
  192. {
  193. if(l>r) return 0;
  194.  
  195. if(tr[x].l==l&&tr[x].r==r)
  196. return tr[x].sum;
  197. if(tr[x].k!=-1)
  198. {
  199. tr[x<<1].k=tr[x].k;tr[x<<1].least=tr[x<<1].k;
  200. tr[x<<1].sum=(ll)tr[x<<1].k*(tr[x<<1].r-tr[x<<1].l+1);
  201. tr[(x<<1)|1].k=tr[x].k;tr[(x<<1)|1].least=tr[(x<<1)|1].k;
  202. tr[(x<<1)|1].sum=(ll)tr[(x<<1)|1].k*(tr[(x<<1)|1].r-tr[(x<<1)|1].l+1);
  203. tr[x].k=-1;
  204. }
  205. int mid=(tr[x].l+tr[x].r)>>1;
  206. if(r<=mid)
  207. return gsum(x<<1,l,r);
  208. else if(l>mid)
  209. return gsum((x<<1)|1,l,r);
  210. else
  211. return gsum(x<<1,l,mid)+gsum((x<<1)|1,mid+1,r);
  212. }
  213. int main()
  214. {
  215. int n;
  216. while(scanf("%d",&n)!=EOF)
  217. {
  218. if(n==0) break;
  219. for(int i=1;i<=n;++i)
  220. scanf("%d",&a[i]);
  221. for(int i=0;i<=n;++i)
  222. f[i]=n+1;
  223. for(int i=n;i>=1;--i)
  224. if(a[i]<n)
  225. {
  226. next[i]=f[a[i]];
  227. f[a[i]]=i;
  228. }
  229. ll ans=0;
  230. memset(exist,false,sizeof(exist));
  231. int l=0;
  232. for(int i=1;i<=n;++i)
  233. {
  234. if(a[i]<n)
  235. {
  236. exist[a[i]]=true;
  237. while(exist[l]) ++l;
  238. }
  239. b[i]=l;
  240. }
  241. build(1,1,n);
  242. ans+=gsum(1,1,n);
  243. for(int i=1;i<n;++i)
  244. {
  245. if(a[i]<n)
  246. {
  247. int r=next[i];
  248. int l=get(1,i,r-1,a[i]);
  249. update(1,l+1,r-1,a[i]);
  250. }
  251. ans+=gsum(1,i+1,n);
  252. }
  253. cout<<ans<<endl;
  254. }
  255. return 0;
  256. }

hdu 4747 Mex的更多相关文章

  1. HDU 4747 Mex 递推/线段树

    题目链接: acm.hdu.edu.cn/showproblem.php?pid=4747 Mex Time Limit: 15000/5000 MS (Java/Others)Memory Limi ...

  2. 【HDU 4747 Mex】线段数

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意:有一组序列a[i](1<=i<=N), 让你求所有的mex(l,r), mex ...

  3. [HDU 4747] Mex (线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 这道题是我去年刚入校队的时候参加网赛的题目. 一年过去了,我依然还是不会做.. 这是我难题计划的 ...

  4. HDU 4747 Mex(线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意:给出一个数列A.计算所有的mex(i,j)之和.1<=i<=j<=n. ...

  5. hdu 4747 Mex (2013 ACM/ICPC Asia Regional Hangzhou Online)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 思路: 比赛打得太菜了,不想写....线段树莽一下 实现代码: #include<iost ...

  6. hdu 4747 mex 线段树+思维

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

  7. HDU 4747 Mex (2013杭州网络赛1010题,线段树)

    Mex Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  8. hdu 4747 Mex( 线段树? 不,区间处理就行(dp?))

    Mex Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  9. HDU 4747 Mex(线段树)(2013 ACM/ICPC Asia Regional Hangzhou Online)

    Problem Description Mex is a function on a set of integers, which is universally used for impartial ...

随机推荐

  1. 安装第三方库出现 Python version 2.7 required, which was not found in the registry

    安装第三方库出现 Python version 2.7 required, which was not found in the registry 建立一个文件 register.py 内容如下. 然 ...

  2. jQuery表单验证插件——jquery.validate.js

    官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation 一.导入js库 <script src="../j ...

  3. static const vs. extern const

    在实现文件(.m文件)中使用static const来定义“只在编译单元内可见的常量”(只在.m文件内可见),由于此类常量不在全局符号表中,所以无须为其名称加类名前缀(一般以k开头). 在头文件中使用 ...

  4. c#下载网页源码的两种方法

    1.WebClient: System.Net.WebClient wc = new System.Net.WebClient(); Byte[] pageData = wc.DownloadData ...

  5. android录像增加时间记录(源码里修改)

    需要做一个功能,录像和播放时都显示录时的时间,参考文章链接找不到了,不好意思,这里记录一下,防止下次找不到了.另一篇关于源码录像的流程请参考 http://www.verydemo.com/demo_ ...

  6. Burning Bridges-ZOJ1588(割边求解)

    Burning Bridges Time Limit: 5 Seconds Memory Limit: 32768 KB Ferry Kingdom is a nice little country ...

  7. python 学习笔记十一 SQLALchemy ORM(进阶篇)

    SqlAlchemy ORM SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据A ...

  8. R----lubridata包介绍学习

    lubridate包,非常强大,能够识别各种类型的日期.字符型和时间型数据,都是格式比较特别的你数据,在处理时,比较麻烦,但是有了lubridate这个包之后,时间处理变得非常简单,这个包函数命名简单 ...

  9. 【转】CentOS下载版本介绍

    官网:http://www.centos.org/ 下载:http://mirror.neu.edu.cn/centos/6.6/isos/ 系统运维:http://www.osyunwei.com/ ...

  10. Hibernate不能自动建数据表解决办法

    首先自己要注意自己的MYSQL版本,然后设置对应的方言 兼容性模式 <property name="hibernate.dialect">org.hibernate.d ...