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. VI中的多行删除与复制

    VI中的多行删除与复制 法一: 单行删除,:(待删除行)d 多行删除 ,:,10d 法二: 光标所在行,dd 光标所在行以下的N行,Ndd 方法1: 光标放到第6行, 输入:2yy 光标放到第9行, ...

  2. Linux下执行的java命令重定向到文件中的方法

    在Linux下通常会执行如:java -version 的命令, 但是,命令只是打印到了屏幕上不能重定向到文件中或标准输出流中. 此时需要将错误输出流重定向到标准输出流中就可以得到了. 比如:java ...

  3. sql server 中一次insert 多条的写法

    1.SELECT INTO FROM语句 注意此处 要求目标表Table2不存在,因为在插入时会自动创建表Table2,并将Table1中指定字段数据复制到Table2中.示例如下 2.INSERT ...

  4. Qt之键盘讲解

    QWSInputMethod详解 注意:这个类不仅仅在嵌入式环境下有效 一个输入法包括了过滤器和可选的图形界面,用来过滤服务器和客户端应用程序之间 的输入事件. 创建自定义的输入法,需要得自QWSIn ...

  5. size_t总结

    1.sizeof返回的必定是无符号整形,在标准c中通过 typedef 将返回值类型定义为size_t. 若用printf输出size_t类型时,C99中定义格式符%zd;若编译器不支持可以尝试%u或 ...

  6. dom4j-1.6.1.jar与dom4j-1.4.jar

    今天在上线的项目中遇到一个很奇怪的问题 File file = new File("O:/20160817/91a2cb1c-62eb-4a31-a1f6-3af8ab71782a/adi6 ...

  7. tomcat域名访问配置

    模拟线上环境,在本地以域名访问系统思路 1.首先在hosts文件将域名映射为本地IP 2.假如服务器80端口已被占用,可以用nginx转发,在nginx/vhosts/abc.com加入如下配置 se ...

  8. img的hover事件闪动

    今天给同学写一个相册照片鼠标浮动显示细节的效果,遇到了闪动的bug,也顺利解决,就写下来跟大家分享. 我使用的是'标签:hover + 标签'的形式,如果使用jquery的mouseover.mous ...

  9. jenkins插件开发-此路是我开

    一:前置环境 1. JDK1.6+ 2. maven已安装 3. jenkins已搭建 4. eclipse已安装(并安装了maven插件) 以上环境可以百度搜索并安装 我的环境是WIN7 64位系统 ...

  10. Writing Text Files On The Client in Oracle Forms 10g

    Below is the example to write file on client in Oracle Forms 10g with webutil library package.Note:  ...