hdu 4747 Mex
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的更多相关文章
- HDU 4747 Mex 递推/线段树
题目链接: acm.hdu.edu.cn/showproblem.php?pid=4747 Mex Time Limit: 15000/5000 MS (Java/Others)Memory Limi ...
- 【HDU 4747 Mex】线段数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意:有一组序列a[i](1<=i<=N), 让你求所有的mex(l,r), mex ...
- [HDU 4747] Mex (线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 这道题是我去年刚入校队的时候参加网赛的题目. 一年过去了,我依然还是不会做.. 这是我难题计划的 ...
- HDU 4747 Mex(线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意:给出一个数列A.计算所有的mex(i,j)之和.1<=i<=j<=n. ...
- hdu 4747 Mex (2013 ACM/ICPC Asia Regional Hangzhou Online)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 思路: 比赛打得太菜了,不想写....线段树莽一下 实现代码: #include<iost ...
- hdu 4747 mex 线段树+思维
http://acm.hdu.edu.cn/showproblem.php?pid=4747 题意: 我们定义mex(l,r)表示一个序列a[l]....a[r]中没有出现过得最小的非负整数, 然后我 ...
- HDU 4747 Mex (2013杭州网络赛1010题,线段树)
Mex Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- hdu 4747 Mex( 线段树? 不,区间处理就行(dp?))
Mex Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- 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 ...
随机推荐
- VI中的多行删除与复制
VI中的多行删除与复制 法一: 单行删除,:(待删除行)d 多行删除 ,:,10d 法二: 光标所在行,dd 光标所在行以下的N行,Ndd 方法1: 光标放到第6行, 输入:2yy 光标放到第9行, ...
- Linux下执行的java命令重定向到文件中的方法
在Linux下通常会执行如:java -version 的命令, 但是,命令只是打印到了屏幕上不能重定向到文件中或标准输出流中. 此时需要将错误输出流重定向到标准输出流中就可以得到了. 比如:java ...
- sql server 中一次insert 多条的写法
1.SELECT INTO FROM语句 注意此处 要求目标表Table2不存在,因为在插入时会自动创建表Table2,并将Table1中指定字段数据复制到Table2中.示例如下 2.INSERT ...
- Qt之键盘讲解
QWSInputMethod详解 注意:这个类不仅仅在嵌入式环境下有效 一个输入法包括了过滤器和可选的图形界面,用来过滤服务器和客户端应用程序之间 的输入事件. 创建自定义的输入法,需要得自QWSIn ...
- size_t总结
1.sizeof返回的必定是无符号整形,在标准c中通过 typedef 将返回值类型定义为size_t. 若用printf输出size_t类型时,C99中定义格式符%zd;若编译器不支持可以尝试%u或 ...
- dom4j-1.6.1.jar与dom4j-1.4.jar
今天在上线的项目中遇到一个很奇怪的问题 File file = new File("O:/20160817/91a2cb1c-62eb-4a31-a1f6-3af8ab71782a/adi6 ...
- tomcat域名访问配置
模拟线上环境,在本地以域名访问系统思路 1.首先在hosts文件将域名映射为本地IP 2.假如服务器80端口已被占用,可以用nginx转发,在nginx/vhosts/abc.com加入如下配置 se ...
- img的hover事件闪动
今天给同学写一个相册照片鼠标浮动显示细节的效果,遇到了闪动的bug,也顺利解决,就写下来跟大家分享. 我使用的是'标签:hover + 标签'的形式,如果使用jquery的mouseover.mous ...
- jenkins插件开发-此路是我开
一:前置环境 1. JDK1.6+ 2. maven已安装 3. jenkins已搭建 4. eclipse已安装(并安装了maven插件) 以上环境可以百度搜索并安装 我的环境是WIN7 64位系统 ...
- 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: ...