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,线段树维护                                这样代码量会比较大,不过耗时少,线段树的解法应该比较标准

两种代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<map> using namespace std; typedef long long ll;
typedef pair<int,int> pp; const int INF=0x3f3f3f3f; const int N=200002;
bool exist[N];
int a[N],next[N],f[N];
int b[N];
int bsh(int l,int r,int k)
{
while(l<=r)
{
int mid=(l+r)>>1;
if(b[mid]<=k) l=mid+1;
else r=mid-1;
}
return r;
}
int main()
{
//freopen("data.in","r",stdin);
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=0;i<=n;++i)
f[i]=n+1;
for(int i=n;i>=1;--i)
if(a[i]<n)
{
next[i]=f[a[i]];
f[a[i]]=i;
}
ll ans=0;
memset(exist,false,sizeof(exist));
ll tmp=0;int l=0;
for(int i=1;i<=n;++i)
{
if(a[i]<n)
{
exist[a[i]]=true;
while(exist[l]) ++l;
}
b[i]=l;
tmp+=b[i];
}
ans=tmp;
for(int i=1;i<n;++i)
{
if(a[i]<n)
{
int r=next[i];
int l=bsh(i,r-1,a[i]);
for(int j=l+1;j<r;++j)
{
tmp-=(b[j]-a[i]);
b[j]=a[i];
}
}
tmp-=b[i];
ans+=tmp;
}
cout<<ans<<endl;
}
return 0;
} #include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<map> using namespace std; typedef long long ll;
typedef pair<int,int> pp; const int INF=0x3f3f3f3f; const int N=200002;
bool exist[N];
int a[N],next[N],f[N];
int b[N];
struct node
{
int l,r,k,least;
ll sum;
}tr[N*4];
void build(int x,int l,int r)
{
tr[x].l=l;tr[x].r=r;tr[x].k=-1;
if(l==r)
{
tr[x].least=b[l];
tr[x].sum=b[l];
return ;
}
int mid=(l+r)>>1;
build((x<<1),l,mid);
build((x<<1)|1,mid+1,r);
tr[x].least=min(tr[x<<1].least,tr[(x<<1)|1].least);
tr[x].sum=(tr[x<<1].sum+tr[(x<<1)|1].sum);
}
void update(int x,int l,int r,int k)
{
if(l>r) return ;
if(tr[x].l==l&&tr[x].r==r)
{
tr[x].least=k;
tr[x].k=k;
tr[x].sum=(ll)k*(tr[x].r-tr[x].l+1);
return ;
}
if(tr[x].k!=-1)
{
tr[x<<1].k=tr[x].k;tr[x<<1].least=tr[x<<1].k;
tr[x<<1].sum=(ll)tr[x<<1].k*(tr[x<<1].r-tr[x<<1].l+1);
tr[(x<<1)|1].k=tr[x].k;tr[(x<<1)|1].least=tr[(x<<1)|1].k;
tr[(x<<1)|1].sum=(ll)tr[(x<<1)|1].k*(tr[(x<<1)|1].r-tr[(x<<1)|1].l+1);
tr[x].k=-1;
}
int mid=(tr[x].l+tr[x].r)>>1;
if(r<=mid)
update(x<<1,l,r,k);
else if(l>mid)
update((x<<1)|1,l,r,k);
else
{
update(x<<1,l,mid,k);
update((x<<1)|1,mid+1,r,k);
}
tr[x].least=min(tr[x<<1].least,tr[(x<<1)|1].least);
tr[x].sum=(tr[x<<1].sum+tr[(x<<1)|1].sum);
tr[x].k=-1;
}
int get(int x,int l,int r,int w)
{
if(tr[x].l==tr[x].r)
{
if(tr[x].least>w)
return (l-1);
return l;
}
if(tr[x].k!=-1)
{
tr[x<<1].k=tr[x].k;tr[x<<1].least=tr[x<<1].k;
tr[x<<1].sum=(ll)tr[x<<1].k*(tr[x<<1].r-tr[x<<1].l+1);
tr[(x<<1)|1].k=tr[x].k;tr[(x<<1)|1].least=tr[(x<<1)|1].k;
tr[(x<<1)|1].sum=(ll)tr[(x<<1)|1].k*(tr[(x<<1)|1].r-tr[(x<<1)|1].l+1);
tr[x].k=-1;
}
int mid=(tr[x].l+tr[x].r)>>1;
if(r<=mid)
return get(x<<1,l,r,w);
else if(l>mid)
return get((x<<1)|1,l,r,w);
else
{
if(tr[(x<<1)|1].least<=w)
return get((x<<1)|1,mid+1,r,w);
else
return get(x<<1,l,mid,w);
}
}
ll gsum(int x,int l,int r)
{
if(l>r) return 0; if(tr[x].l==l&&tr[x].r==r)
return tr[x].sum;
if(tr[x].k!=-1)
{
tr[x<<1].k=tr[x].k;tr[x<<1].least=tr[x<<1].k;
tr[x<<1].sum=(ll)tr[x<<1].k*(tr[x<<1].r-tr[x<<1].l+1);
tr[(x<<1)|1].k=tr[x].k;tr[(x<<1)|1].least=tr[(x<<1)|1].k;
tr[(x<<1)|1].sum=(ll)tr[(x<<1)|1].k*(tr[(x<<1)|1].r-tr[(x<<1)|1].l+1);
tr[x].k=-1;
}
int mid=(tr[x].l+tr[x].r)>>1;
if(r<=mid)
return gsum(x<<1,l,r);
else if(l>mid)
return gsum((x<<1)|1,l,r);
else
return gsum(x<<1,l,mid)+gsum((x<<1)|1,mid+1,r);
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=0;i<=n;++i)
f[i]=n+1;
for(int i=n;i>=1;--i)
if(a[i]<n)
{
next[i]=f[a[i]];
f[a[i]]=i;
}
ll ans=0;
memset(exist,false,sizeof(exist));
int l=0;
for(int i=1;i<=n;++i)
{
if(a[i]<n)
{
exist[a[i]]=true;
while(exist[l]) ++l;
}
b[i]=l;
}
build(1,1,n);
ans+=gsum(1,1,n);
for(int i=1;i<n;++i)
{
if(a[i]<n)
{
int r=next[i];
int l=get(1,i,r-1,a[i]);
update(1,l+1,r-1,a[i]);
}
ans+=gsum(1,i+1,n);
}
cout<<ans<<endl;
}
return 0;
}

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. Oracle中的自动增长字段

    Oracle中的自动增长字段 Oracle 中不像MYSQL 和MSSQLServer 中那样指定一个列为自动增长列的方式,不过在Oracle中可以通过SEQUENCE序列来实现自动增长字段. 在Or ...

  2. js 父窗体

    1.关闭  父窗体 window.opener.opener=null;window.opener.close() 2.刷新父窗体 JS刷新父窗口的几种方式   浮层内嵌iframe及frame集合窗 ...

  3. Linux按键驱动程序设计--从简单到不简单【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/51399353 混杂设备驱动模型: 1. 混杂设备描述 在Linux系统中,存在一 ...

  4. linux下cmake编译安装、配置和卸载mysql

    WIN10下虚拟机:VMware workstation 12 PRO 安装 # 1.查看系统版本 [root@vm-xiluhua][/home/xiluhua]$ cat /etc/redhat- ...

  5. Codeforces 749B:Parallelogram is Back(计算几何)

    http://codeforces.com/problemset/problem/749/B 题意:已知平行四边形三个顶点,求另外一个顶点可能的位置. 思路:用向量来做. #include <c ...

  6. 关于JQ的$.deferred函数。参考网络文档

    由于jQuery版本问题对Deferred对象的实现有所不同,具体请参照jQuery api:   jQuery.Deferred()基于Promises/A规范实现,因为jQuery本身的设计风格, ...

  7. Unity碰撞器触发关系测试

    本文刚体有关的内容不再赘述,主要测试碰撞器和触发器的消息关系. 刚体在这篇有测试:U3D刚体测试1-刚体非刚体物体非Kinematic等之间的碰撞关系 碰撞器测试结果: 1.A对象为Collider, ...

  8. RCP: P2 Update两个烦人bug和解决办法

    问题 Eclipse新的P2 Update机制,使用起来很方便,如果使用P2 plugin自带的UI,开发者完全不用写任何代码 即可实现application的在线更新. 但是P2 Update至少有 ...

  9. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序创建更复杂的数据模型

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第六篇:为ASP.NET MVC应用程序 ...

  10. vs2012编译Qwt

    主题:vs2012编译Qwt ------------------------------------------------------------------------- 参照网络地址: htt ...