solution by Mr.gtf

一道简单的递推

首先我们对树高从大到小排序

很容易得到递推式

ans[i]=Σans[j] (j<i && h[j]-h[i]<=K)

朴素做法暴力枚举,暴力for j from 1 to i-1

聪明一点能发现满足条件的j一定是i之前连续的一段,只要从i-1开始向前for到不满足为止

这样做最坏情况依然是O(nK)或者O(n^2)

事实上,只要再深入思考,就能发现,对于每个i,满足条件的最小的j是单调不降的。

所以我们只需要准备一个队列,在求i答案时将队列首不满足条件的j踢出,在i求出答案后入队,需要维护一个队列内的下标的ans和。

复杂度O(n)

My Code

#define N 1000010
#define MOD 1000000007 using namespace std; int n , a[N] , f[N] , k; int z[N] , head , tail , done; int main()
{
// freopen("tree.in" , "r" , stdin);
// freopen("tree.out" , "w" , stdout);
scanf("%d%d",&n,&k);
for (int i = 1 ; i <= n ; i++)
cin >> a[i];
sort(a + 1 , a + 1 + n);
a[0] = 0;
f[0] = 1;
done = 1;
for (int i = 1 ; i <= n ; i++)
{
while(a[z[head]] + k < a[i] && z[head] < i)
{
head++;
}
f[i] = done;
z[++tail] = i;
done += f[i];
done %= MOD;
/*for (int j = i - 1 ; j >= 0 ;j--) //不优化40分
{
if(a[i] - a[j] <= k)
{
f[i] += f[j];
f[i] %= MOD;
}
else
break;
}*/
}
printf("%d\n" , f[n]);
return 0;
}

Teacher's Code

#include <iostream>
#include <cstdio>
#include <algorithm> using namespace std; const int MaxN = 1e6 + 50;
const int MOD = 1e9 + 7;
int n, K, h[MaxN];
int ans[MaxN]; struct Queue
{
const static int MAX_SIZE = 1e6;
int data[MAX_SIZE];
int head, tail; Queue() : head(0), tail(0) {} inline static int inc(int p)
{
++p;
return (p == MAX_SIZE) ? 0 : p;
} void push(int x); void pop(); int front(); inline bool empty();
}; Queue q; int main()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout); scanf("%d%d", &n, &K);
for (int i = 0; i < n; ++i) scanf("%d", &h[i]);
sort(h, h + n, greater<int>());
h[n] = 0;
ans[0] = 1;
q.push(0);
int qSum = ans[0]; for (int i = 1; i <= n; ++i) {
while (!q.empty()) {
int j = q.front();
if (h[j] - h[i] > K) {
qSum = ((qSum - ans[j]) % MOD + MOD) % MOD;
q.pop();
} else break;
}
ans[i] = qSum;
q.push(i);
qSum = (qSum + ans[i]) % MOD;
} printf("%d\n", ans[n]);
return 0;
}
//队列操作
void Queue::push(int x)
{
if (inc(tail) == head) throw x;
data[tail] = x;
tail = inc(tail);
} void Queue::pop()
{
if (empty()) throw head;
head = inc(head);
} int Queue::front()
{
if (empty()) throw head;
return data[head];
} inline bool Queue::empty()
{
return head == tail;
}

【例】最长等差子序列

题目描述

给你一个以正整数构成的序列,求它的最长等差子序列的长度

难度1 n<=1000,a[i]<=1000

难度2 n<=100,a[i]<=10^9

解析

首先离散化!

注意到难度二n只有100,而a很大

大致就是把一个数组如

a 111 44 76538 0 342566677

转成

a 3 2 4 1 5

再调用

然后发现这题与上题的区别就在于 公差不定 和 必须等差

公差不定其实就枚举公差,再重复上个题的操作

必须等差就把上个题的判断条件改掉(h[j] - h[i] > K 改成 h[j] - h[i] == k)

复杂度

公差个数nn

难度一:1000 * 1000 * 1000

难度二:10^9 ^ 100 ^ 100

第一层循环公差,第二层循环序列右端点,第三层循环上一个元素的下表

优化:把第三层循环用数组存起来

f[i]:到第i个元素的最长等差序列

k:公差

\(f[k][i] = max{f[k][j] | a[j] + k == a[i]}\)

定义p[k][a[j]] = max{f[k][j] | a[j] + k = a[i]}

就能把O(n)的循环变成 O(1)的查询

写的时候可以滚掉一维公差k,省空间

注意负公差

T1飞跃树林 && 【最长等差子序列】的更多相关文章

  1. BZOJ 2124: 等差子序列

    Sol 线段树+Hash. 首先暴力 等差子序列至少3项就可以了,就枚举中项,枚举公差就可以了,只需要一个数在中项前出现,另一个数在中项前没出现过就可以了.复杂度 \(O(n^2)\) 然后我想了一个 ...

  2. 最长公共子序列(LCS)和最长递增子序列(LIS)的求解

    一.最长公共子序列 经典的动态规划问题,大概的陈述如下: 给定两个序列a1,a2,a3,a4,a5,a6......和b1,b2,b3,b4,b5,b6.......,要求这样的序列使得c同时是这两个 ...

  3. [bzoj2124]等差子序列(hash+树状数组)

    我又来更博啦     2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 941  Solved: 348[Submit][Statu ...

  4. NOIP200407合唱队形+最长上升子序列O(n^2)详解

    合唱队形解题报告 2016-05-12   4:30——6:45 NOIP200407合唱队形 难度级别:A: 运行时间限制:1000ms: 运行空间限制:256000KB: 代码长度限制:20000 ...

  5. BZOJ 2124等差子序列 线段树&&hash

    [题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len& ...

  6. 动态规划:最长上升子序列(LIS)

    转载请注明原文地址:http://www.cnblogs.com/GodA/p/5180560.html 学习动态规划问题(DP问题)中,其中有一个知识点叫最长上升子序列(longest  incre ...

  7. Longest Common Substring(最长公共子序列)

    Longest Common Substring Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...

  8. [bzoj3173]最长上升子序列_非旋转Treap

    最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...

  9. LCSS最长公共子序列算法

    0.论文基本介绍以及相关内容 分析移动用户位置的相似性,提取移动用户的相似路径在出行路径预测.兴趣区域发现.轨迹聚类.个性化路径推荐等领域具有广泛的应用. 重点:利用移动用户定位数据找到合适轨迹的表示 ...

随机推荐

  1. 我们为什么会删除不了集群的 Namespace?

    作者 | 声东  阿里云售后技术专家 导读:阿里云售后技术团队的同学,每天都在处理各式各样千奇百怪的线上问题.常见的有网络连接失败.服务器宕机.性能不达标及请求响应慢等.但如果要评选的话,什么问题看起 ...

  2. tantivy&lucene功能,写入性能对比

    硬件概述:cpu:24,内存:20g,磁盘:10*2.7T. 写入性能:(不对ip进行添加geo信息). 写入性能对比 速度 Commit耗时(秒) 500*1000条 Bulk耗时(秒) 1000条 ...

  3. js 日期增减

    js 的 Date 对象提供了许多方法,可以获取日期的年.月.日等信息,也可以修改年.月.日 日期的增减可以使用setFullYear().setMonth().setDate() 等方法 exp: ...

  4. js删除数组的某个元素

    最近在刷算法题,我是用js语言去写的,其中一题需要删除数组的某个元素,查了一下资料,总结一下 使用splice()方法 array.splice(start[, deleteCount[, item1 ...

  5. python文档字符串(函数使用说明)

    关键字: 函数说明.help()函数 1.效果图: 2.代码: # 文档字符串( doc str) 是 函数使用说明 # 用法: 在函数第一行写一个字符串 def fn(*nums): ''' 函数的 ...

  6. java 中文乱码问题

    1.要记住的事实 java的class文件是utf-8编码的,jvm使用utf-16,而java的字符串使用unicode编码 2.java支持的字符集 java支持的字符集可以通过java.nio. ...

  7. VSCode前端 插件

    https://www.cnblogs.com/karthuslorin/p/8577224.html

  8. DirectX11 Windows Windows SDK--28 计算着色器:波浪(水波)

    前言 有关计算着色器的基础其实并不是很多.接下来继续讲解如何使用计算着色器实现水波效果,即龙书中所实现的水波.但是光看代码可是完全看不出来是在做什么的.个人根据书中所给的参考书籍找到了对应的实现原理, ...

  9. Kafka Topic 体系结构 - 复制 故障转移 并行处理

    本文介绍了 Kafka Topic 的体系结构,并讨论了如何使用分区进行故障转移和并行处理. 1. Kafka Topic, Log, Partition Kafka Topic(主题) 是一个有名字 ...

  10. Java入门 - 面向对象 - 01.继承

    原文地址:http://www.work100.net/training/java-inheritance.html 更多教程:光束云 - 免费课程 继承 序号 文内章节 视频 1 概述 2 继承的特 ...