POJ 3419 Difference Is Beautiful(RMQ变形)
题意: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变形)的更多相关文章
- POJ 3419 Difference Is Beautiful(RMQ+二分 或者 模拟)
Difference Is Beautiful Time Limit:5000MS Memory Limit:65536KB 64bit IO Format:%lld & %l ...
- POJ 3419 Difference Is Beautiful (DP + 二分 + rmq)
题意:给n个数(n<=200000),每个数的绝对值不超过(10^6),有m个查询(m<=200000),每次查询区间[a,b]中连续的没有相同数的的最大长度. 析:由于n太大,无法暴力, ...
- POJ 3419 Difference Is Beautiful
先处理出每一个i位置向左最远能到达的位置L[i].每一次询问,要找到L,R区间中的p位置,p位置左边的L[i]都是小于L的,p位置开始,到R位置,L[i]都大于等于L,对于前者,最大值为p-L,后者求 ...
- poj 3368 Frequent values(RMQ)
题目:http://poj.org/problem?id=3368 题意:给定n个数,顺序为非下降,询问某个区间内的数出现最多的数的 出现次数.. 大白书上的 例题..算是RMQ变形了, 对 原数组重 ...
- POJ 3635 - Full Tank? - [最短路变形][手写二叉堆优化Dijkstra][配对堆优化Dijkstra]
题目链接:http://poj.org/problem?id=3635 题意题解等均参考:POJ 3635 - Full Tank? - [最短路变形][优先队列优化Dijkstra]. 一些口胡: ...
- POJ 2019 Cornfields [二维RMQ]
题目传送门 Cornfields Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 7963 Accepted: 3822 ...
- POJ 1696 - Space Ant 凸包的变形
Technorati Tags: POJ,计算几何,凸包 初学计算几何,引入polygon后的第一个挑战--凸包 此题可用凸包算法做,只要把压入凸包的点从原集合中排除即可,最终形成图形为螺旋线. 关于 ...
- poj 3264 Balanced Lineup(RMQ裸题)
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 43168 Accepted: 20276 ...
- POJ 3264 Balanced Lineup(RMQ)
点我看题目 题意 :N头奶牛,Q次询问,然后给你每一头奶牛的身高,每一次询问都给你两个数,x y,代表着从x位置上的奶牛到y位置上的奶牛身高最高的和最矮的相差多少. 思路 : 刚好符合RMQ的那个求区 ...
随机推荐
- DevSecOps 实施篇!系列(二)
想在自己公司建立 DevSecOps 计划?没问题,企业规模无论大小,都可轻松实现.这里有5个基本的 DevSecOps 原则可以帮助你启动.当然,如果你对 DevSecOps 还不太熟悉,不妨先看看 ...
- URAL 1146 Maximum Sum & HDU 1081 To The Max (DP)
点我看题目 题意 : 给你一个n*n的矩阵,让你找一个子矩阵要求和最大. 思路 : 这个题都看了好多天了,一直不会做,今天娅楠美女给讲了,要转化成一维的,也就是说每一列存的是前几列的和,也就是说 0 ...
- QString和char字符数组之间的转换(QTextCodec.toUnicode方法,特别注意\0的问题)
How can I convert a QString to char* and vice versa ?(trolltech) Answer:In order to convert a QStrin ...
- C#基础精华06(Linq To XML,读取xml文件,写入xml)
1.XML概述: 可扩展标记语言XML(eXtensible Markup Language)是一种简单灵活的文本格式的可扩展标记语言,侧重于存储数据. 2.XML特点 xml 标记语言 html x ...
- Java IO3:字符流
字符流 字节流提供了处理任何类型输入/输出操作的功能(对于计算机而言,一切都是0 和1,只需把数据以字节形式表示就够了),但它们不可以直接操作Unicode字符,一个Unicode字符占用2个字节,而 ...
- Git教程之分支管理之二
分支管理策略 通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息.如果要强制禁用Fast forward模式,Git就会在merge时生成一个 ...
- Java API ——Scanner类
1.Scanner类概述 JDK5以后用于获取用户的键盘输入,一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器.Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空 ...
- 深入解析字符串的比较方法:“==”操作符;String.Equals方法;String.Compare方法;String.CompareOrdinal方法。
1:要判断2个字符串变量是否相等,最高效的方法是看它们是否指向相同的内存地址.前面使用RefernceEquals方法来比较.如果2个变量指向的是不同的内存地址,那么就需要逐字符的比较2个字符串的变量 ...
- XmlDocument类
XmlDocument类是.NET框架的DOC解析器.XmlDocument将XML视为树状结构,它装载XML文档,并在内存中构建该文档的树状结构.下面来看下XmlDocument提供了哪些功能. 一 ...
- 如何查看你的 memcached 的状态
最近略忙,好久没有更新博客了,已长草,今天来除下草,好了,不废话了,开始! 现在很多web服务都会用到 memcached ,如何知道你的 memcached 是否正常工作,命中率如何呢,本文简单介 ...