小明系列问题——小明序列

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)

Total Submission(s): 1553    Accepted Submission(s): 457

Problem Description
  大家都知道小明最喜欢研究跟序列有关的问题了,但是也就由于这样,小明差点儿已经玩遍各种序列问题了。可怜的小明苦苦地在各大站点上寻找着新的序列问题,但是找来找去都是自己早已研究过的序列。

小明想既然找不到,那就自己来发明一个新的序列问题吧!小明想啊想,最终想出了一个新的序列问题,他欣喜若狂,由于是自己想出来的。于是将其新序列问题命名为“小明序列”。

  提起小明序列。他给出的定义是这种:

  ①首先定义S为一个有序序列。S={ A1 , A2 , A3 , ... , An }。n为元素个数 ;

  ②然后定义Sub为S中取出的一个子序列,Sub={ Ai1 , Ai2 , Ai3 , ... , Aim },m为元素个数 ;

  ③当中Sub满足 Ai1 < Ai2 < Ai3 < ... < Aij-1 < Aij < Aij+1 < ... < Aim ;

  ④同一时候Sub满足对于随意相连的两个Aij-1与Aij都有 ij - ij-1 > d (1 < j <= m, d为给定的整数);

  ⑤显然满足这种Sub子序列会有许很多多。而在取出的这些子序列Sub中,元素个数最多的称为“小明序列”(即m最大的一个Sub子序列)。

  比如:序列S={2,1,3,4} 。当中d=1;

  可得“小明序列”的m=2。

即Sub={2,3}或者{2,4}或者{1,4}都是“小明序列”。

  当小明发明了“小明序列”那一刻,情绪很激动,以至于头脑凌乱,于是他想请你来帮他算算在给定的S序列以及整数d的情况下,“小明序列”中的元素须要多少个呢?

 
Input
  输入数据多组,处理到文件结束;

  输入的第一行为两个正整数 n 和 d;(1<=n<=10^5 , 0<=d<=10^5)

  输入的第二行为n个整数A1 , A2 , A3 , ... , An。表示S序列的n个元素。(0<=Ai<=10^5)
 
Output
  请对每组数据输出“小明序列”中的元素须要多少个,每组測试数据输出一行。

 
Sample Input
2 0
1 2
5 1
3 4 5 1 2
5 2
3 4 5 1 2
 
Sample Output
2
2
1
 
Source
 
Recommend
liuyiding   |   We have carefully selected several similar problems for you:  4822 4821 4820 4819 

pid=4818">4818 

题意:
给你一个序列。序列长度为n(n<=10^5)要你求最长上升子序列A(0<=A[i]<=10^5)。可是跟一般的最长上升子序列有点不同的是。序列中相邻的两个数下标差要大于d。
思路:
解法一:
O(n*n)的算法都非常easy想到。dp[i]表示序列以i结尾的最大长度。那么dp[i]=max(dp[j])+1.a[j]<a[i],i-j>d。
可是n范围10^5这个算法肯定要超时。

大概推測时间复杂度O(n*log2(n))就差点儿相同了。

看来得优化下dp方程。

假设可以高速的得到max(dp[j])的话那么状态转移仅仅须要O(1)的时间。如今关键是怎么高速的到这个了。

比A[i]小且下标至少比i小d最大的DP值。

这不就是线段树擅长的么。并且空间也同意。可是下标小d怎么处理延迟d个单位更新即可了.

具体见代码:
#include <iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn=100010;
int maxv[maxn<<2],dp[maxn],val[maxn],pre[maxn];
void update(int L,int R,int p,int d,int k)
{
int ls,rs,mid;
if(L==R)
{
maxv[k]=max(maxv[k],d);
return ;
}
ls=k<<1;
rs=ls|1;
mid=(L+R)>>1;
if(p<=mid)
update(L,mid,p,d,ls);
else
update(mid+1,R,p,d,rs);
maxv[k]=max(maxv[ls],maxv[rs]);
}
int qu(int L,int R,int l,int r,int k)//区间最值
{
int ls,rs,mid;
if(l==L&&r==R)
return maxv[k];
ls=k<<1;
rs=ls|1;
mid=(L+R)>>1;
if(l>mid)
return qu(mid+1,R,l,r,rs);
else if(r<=mid)
return qu(L,mid,l,r,ls);
else
return max(qu(L,mid,l,mid,ls),qu(mid+1,R,mid+1,r,rs));
}
int main()
{
int n,d,i,lim,ans; while(~scanf("%d%d",&n,&d))
{
memset(maxv,0,sizeof maxv);
memset(dp,0,sizeof dp);
lim=0,ans=1;
for(i=1;i<=n;i++)
{
scanf("%d",&val[i]);
val[i]+=2;
lim=max(lim,val[i]);
}
for(i=1;i<=d;i++)
dp[val[i]]=1,pre[i]=1;//pre起到队列的作用。先把要跟新的值存起来。 等距离大于d的时候再更新
for(i=d+1;i<=n;i++)
{
if(i==1)//d=0单独处理下
{
dp[val[i]]=1;
pre[i-d]=1;
update(1,lim,val[i-d],pre[i-d],1);
continue;
}
dp[val[i]]=max(qu(1,lim,1,val[i]-1,1)+1,dp[val[i]]);
pre[i]=dp[val[i]];
update(1,lim,val[i-d],pre[i-d],1);
ans=max(ans,dp[val[i]]);
}
printf("%d\n",ans);
}
return 0;
}

解法二:用经典的LIS扩展。dp[i]表示长度为i的序列结尾最小为dp[i]。

经典的LIS是每处理完一个单位就要更新dp即d=0的情况。可是如今得到的新值先保存在pre[i]中。

由于它仅仅会影响到i+d以后的dp值。

所以到那时才干更新。

具体见代码。
#include<algorithm>
#include<iostream>
#include<string.h>
#include<sstream>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<string>
#include<queue>
#include<set>
#include<map>
//#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
const double PI=acos(-1.0);
const int maxn=100010;
//typedef __int64 ll;
int dp[maxn],arr[maxn],pre[maxn],lim;
int bin(int x)
{
int low,hi,mid,ans=-1;
low=0,hi=lim;
while(low<=hi)
{
mid=(low+hi)>>1;
if(dp[mid]<x)
ans=mid,low=mid+1;
else
hi=mid-1;
}
return ans;
}
int main()
{
int n,d,i,ans; while(~scanf("%d%d",&n,&d))
{
for(i=1;i<=n;i++)
scanf("%d",&arr[i]);
dp[0]=-INF,lim=0,ans=1;
for(i=1;i<=d;i++)
pre[i]=1;
for(i=d+1;i<=n;i++)
{
pre[i]=bin(arr[i])+1;//先把值保存起来。等距离超过d再更新
ans=max(ans,pre[i]);//注意随时更新答案。
if(pre[i-d]>lim)
lim=pre[i-d],dp[lim]=arr[i-d];
else
dp[pre[i-d]]=min(dp[pre[i-d]],arr[i-d]);
}
printf("%d\n",ans);
}
return 0;
}

 

hdu 4521 小明系列问题——小明序列(线段树+DP或扩展成经典的LIS)的更多相关文章

  1. hdu 4521 小明系列问题——小明序列 线段树+二分

    小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Pro ...

  2. 小明系列问题――小明序列(LIS)

    小明系列问题――小明序列 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit ...

  3. hdu----(4521)小明系列问题——小明序列

    小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tota ...

  4. 小明系列问题——小明序列(Lis 相距大于d的单调上升子序列)

    小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Tot ...

  5. 2018.07.08 hdu4521 小明系列问题——小明序列(线段树+简单dp)

    小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Proble ...

  6. hdu 1556:Color the ball(线段树,区间更新,经典题)

    Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  8. Snacks HDU 5692 dfs序列+线段树

    Snacks HDU 5692 dfs序列+线段树 题意 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充, ...

  9. HDU 4521 小明系列问题——小明序列 (线段树 单点更新)

    题目连接 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来 ...

随机推荐

  1. 折腾开源WRT的AC无线路由之路-5

    -在Mac上设置无password连接SSH 1. 生成SSH密钥对 <pre name="code" class="html">ssh-keyge ...

  2. hibernate 管理 Session(单独使用session,非spring)

    Hibernate 自身提供了三种管理 Session 对象的方法 Session 对象的生命周期与本地线程绑定 Session 对象的生命周期与 JTA 事务绑定 Hibernate 托付程序管理 ...

  3. python爬虫系列序

    关于爬虫的了解,始于看到这篇分析从数据角度解析福州美食,和上份工作中的短暂参与. 长长短短持续近一年的时间,对其态度越来越明晰,噢原来这就是我想从事的工作. 于是想要系统学习的心理便弥散开来…… 参考 ...

  4. CSDN的技术问题

    说CSDN是国内最大最好的技术论坛.预计不会有人反对,可是...CSDN的人,如管理员懂技术吗? 假设您长期在CSDN混.您就会发现他们相当懂得......强奸技术!

  5. 0x21 剪枝

    这一章真是心态崩,剪枝太玄学啦,特别是那个搜索顺序我靠真的... poj1011 枚举答案,搜索记录当前到第几根木棒. 剪枝:1.从大到小排序 2.排除等效,这个感觉还行,就是木棒按大小顺序进去,去除 ...

  6. docker迁移步骤

    1. 创建快照:docker commit -p 30b8f18f20b4 container-backup (可以通过docker images 查看docker镜像) 2. 镜像保存在本地机器中: ...

  7. Spark SQL概念学习系列之用户自定义函数

    不多说,直接上干货! 用户自定义函数 注册udf 我们可以使用Spark 支持的编程语言编写好函数,然后通过Spark SQL 内建的方法传递进来,非常便捷地注册我们自己的UDF 在Scala 和Py ...

  8. 洛谷P3356 火星探险问题(费用流)

    题目描述 火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车.登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动.探测车在移动中还必须采集岩石标本.每一块岩石标本由最先遇到它的探测 ...

  9. Codeforces Round #282 (Div. 2) A

    解题思路:用数组将每一个显示数字可能表示的数字种数存储起来即可 反思:第一次做的时候没有做出来是因为题意理解错误,第二次WA是因为情况没有考虑完全,1对应有7个数字,5对应有4个数字       A. ...

  10. CREC 2017

    A:Assignment Algorithm #include <bits/stdc++.h> using namespace std; ][]; ][],n,m,ans=,A,B,l=, ...