题意:N个数,M个询问,每个询问为一个区间,求区间最长连续子序列,要求每个数都不同(perfect sequence,简称PS)。

题解:很容易求出以每个数为结尾的ps,也就是求区间的最大值。有一个不同就是长度可能会超出询问范围,所以先对PS的首位置二分,然后RMQ。注意一点,序列有可能出现负数,所以先加最大值变为正数。其实也不算变形,挺裸的……

这题卡线段树,然而我只会线段树,心塞……

代码(树状数组):

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = ; int a[N], pos[N], len[N], nt[N]; #define lowbit(x) ((x)&(-x))
int idx[N]; void init(int n)
{
for(int i=;i<=n;i++) {
idx[i] = len[i];
for(int j=;j<lowbit(i);j<<=){
idx[i]=max(idx[i],idx[i-j]);
}
}
} int query(int l, int r)
{
int ans=len[r];
while(true) {
ans=max(ans,len[r]);
if(r==l) break;
for(r-=;r-l>=lowbit(r);r-=lowbit(r)){
ans=max(ans,idx[r]);
}
}
return ans;
} int main()
{
int n, m;
while (~scanf("%d%d", &n, &m)) {
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
a[i] += ;
}
memset(pos, , sizeof pos);
nt[] = ;
for (int i = ; i <= n; ++i) {
nt[i] = max(nt[i-], pos[a[i]]+);//nt[i]以i为结尾的最长子序列的首端
len[i] = i-nt[i]+;
pos[a[i]] = i;
}
init(n); while (m--) {
int l, r;
scanf("%d%d", &l, &r); l++, r++;
int p = upper_bound(nt+, nt++n, l) - nt;
int ans = ;
if (p > r) {
printf("%d\n", r-l+);
continue;
}
if (p > l) ans = p-l;
ans = max(ans, query(p, r));
printf("%d\n", ans);
}
}
return ;
}

代码(ST算法):

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = ; int a[N], pos[N], len[N], nt[N];
int f[N][]; void init(int n)
{
// f[i,j]表示[i,i+2^j-1]区间最大值
// f[i,j]=max(d[i,j-1], d[i+2^(j-1),j-1])
for (int i = ; i <= n; ++i) f[i][] = len[i];
for (int j = ; (<<j) <= n; ++j)
for (int i = ; i+j- <= n; ++i)
f[i][j] = max(f[i][j-], f[i+(<<j-)][j-]);
} int query(int l, int r)
{
int k = ;
while ((<<k+ <= r-l+)) ++k;
return max(f[l][k], f[r-(<<k)+][k]);
} int main()
{
int n, m;
while (~scanf("%d%d", &n, &m)) {
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
a[i] += ;
}
memset(pos, , sizeof pos);
nt[] = ;
for (int i = ; i <= n; ++i) {
nt[i] = max(nt[i-], pos[a[i]]+);//nt[i]以i为结尾的最长子序列的首端
len[i] = i-nt[i]+;
pos[a[i]] = i;
}
init(n); while (m--) {
int l, r;
scanf("%d%d", &l, &r); l++, r++;
int p = upper_bound(nt+, nt++n, l) - nt;
int ans = ;
if (p > r) {
printf("%d\n", r-l+);
continue;
}
if (p > l) ans = p-l;
ans = max(ans, query(p, r));
printf("%d\n", ans);
}
}
return ;
}

还有一种网上流传的算法,类似kmp。想法很巧妙,但是最坏复杂度貌似是O(n^2),不过也能A这道题。而且速度不必上面慢。数据水吧~

nt[i]记录想要字串中含有a[(i+1)-pos[i+1]]的最大位置。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = ; int a[N], pos[N], len[N], nt[N]; int main()
{
int n, m;
while (~scanf("%d%d", &n, &m)) {
for (int i = ; i <= n; ++i) {
scanf("%d", a+i);
a[i] += ;
}
memset(pos, , sizeof pos);
len[] = ; nt[] = ;
for (int i = ; i <= n; ++i) {
if (len[i-]+ <= i-pos[a[i]]) {
len[i] = len[i-]+;
nt[i] = nt[i-];
} else {
len[i] = i-pos[a[i]];
nt[i] = i-;
}
pos[ a[i] ] = i;
//printf("%d %d %d\n", len[i], nt[i], pos[a[i]]);
}
while (m--) {
int l, r;
scanf("%d%d", &l, &r); l++, r++;
int res = len[r];
if (res >= r-l+) {
printf("%d\n", r-l+);
continue;
}
while (nt[r] > ) {
r = nt[r];
res = max(res, min(len[r], r-l+));
if (res >= r-l+) {
break;
}
}
printf("%d\n", res);
}
}
return ;
}

POJ 3419 Difference Is Beautiful(RMQ变形)的更多相关文章

  1. POJ 3419 Difference Is Beautiful(RMQ+二分 或者 模拟)

    Difference Is Beautiful Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%lld & %l ...

  2. POJ 3419 Difference Is Beautiful (DP + 二分 + rmq)

    题意:给n个数(n<=200000),每个数的绝对值不超过(10^6),有m个查询(m<=200000),每次查询区间[a,b]中连续的没有相同数的的最大长度. 析:由于n太大,无法暴力, ...

  3. POJ 3419 Difference Is Beautiful

    先处理出每一个i位置向左最远能到达的位置L[i].每一次询问,要找到L,R区间中的p位置,p位置左边的L[i]都是小于L的,p位置开始,到R位置,L[i]都大于等于L,对于前者,最大值为p-L,后者求 ...

  4. poj 3368 Frequent values(RMQ)

    题目:http://poj.org/problem?id=3368 题意:给定n个数,顺序为非下降,询问某个区间内的数出现最多的数的 出现次数.. 大白书上的 例题..算是RMQ变形了, 对 原数组重 ...

  5. POJ 3635 - Full Tank? - [最短路变形][手写二叉堆优化Dijkstra][配对堆优化Dijkstra]

    题目链接:http://poj.org/problem?id=3635 题意题解等均参考:POJ 3635 - Full Tank? - [最短路变形][优先队列优化Dijkstra]. 一些口胡: ...

  6. POJ 2019 Cornfields [二维RMQ]

    题目传送门 Cornfields Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 7963   Accepted: 3822 ...

  7. POJ 1696 - Space Ant 凸包的变形

    Technorati Tags: POJ,计算几何,凸包 初学计算几何,引入polygon后的第一个挑战--凸包 此题可用凸包算法做,只要把压入凸包的点从原集合中排除即可,最终形成图形为螺旋线. 关于 ...

  8. poj 3264 Balanced Lineup(RMQ裸题)

    Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 43168   Accepted: 20276 ...

  9. POJ 3264 Balanced Lineup(RMQ)

    点我看题目 题意 :N头奶牛,Q次询问,然后给你每一头奶牛的身高,每一次询问都给你两个数,x y,代表着从x位置上的奶牛到y位置上的奶牛身高最高的和最矮的相差多少. 思路 : 刚好符合RMQ的那个求区 ...

随机推荐

  1. hdu 4035 Maze 概率DP

        题意:    有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树,    从结点1出发,开始走,在每个结点i都有3种可能:        1.被杀死,回到结点1处(概率为ki)      ...

  2. 【前端学习】【jQuery选择器】

    jQuery选择器     jQuery选择器 本文内容引自于单东林<锋利的jQuery>,未经原作者准许,禁止以商业目的转载发布! 选择器是jQuery的根基,在jQuery中,对事件处 ...

  3. 深入理解JVM--JVM垃圾回收机制

    Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放空间,既要写构造函数,又要写析构函数,很多时候都 ...

  4. Oracle学习笔记之数据类型

    1. mysql和oracle做数据同步.其中表的一个字段在mysql中设置为varchar(6),Oracle中为varchar2(6)   但mysql中能正常存放的数据同步到oracle中却抱O ...

  5. 查看32bit的ARM(比如ARMv7)反汇编

    1.使用./arm-eabi-as test.S -o test.o编译 2.使用./arm-eabi-objdump -d test.o反汇编

  6. 工具----IcoFX

    IcoFX IcoFX 是一款免费的图标编辑工具,让您轻松创建 Windows XP 和 Windows Vista 图标. 在编辑区您可以轻松的预览.保存.更改您的图标.您可以将您喜欢的图像转换为图 ...

  7. 【原创】基于ZYNQ7000的交叉编译工具链Qt+OpenCV+ffmpeg等库支持总结(二)

    承接上文http://www.cnblogs.com/bombe1013/p/3294301.html,我们接下来说说Qt的移植与安装. 很喜欢Qt这个库以及Qt creater这个IDE,其实个人觉 ...

  8. 新版本的tlplayer for android ,TigerLeapMC for windows发布了

    tlplayer for android 新版本修正了图像倾斜等等问题,增加了动态水印功能. 支持hls(m3u8),http,rtsp,mms,rtmp等网络协议. 声明tlplayer 上的变速不 ...

  9. struts2的action中获得request response session 对象

    在struts2中有两种方式可以得到这些对象 1.非IoC方式 要获得上述对象,关键Struts 2中com.opensymphony.xwork2.ActionContext类.我们可以通过它的静态 ...

  10. mssql查找备注(text,ntext)类型字段为空的方法

    在sql语句中,如果查找某个文本字段值为空的,可以用select * from 表 where 字段='' ,但是如果这个字段数据类型是text或者ntext,那上面的sql语句就要出错了. 解决办法 ...