POJ 3368 RMQ-ST
一直感觉RMQ水,没自己写过,今天写了一道题,算是完全独立写的,这感觉好久没有了...
一直以来,都是为了亚洲赛学算法,出现了几个问题:
1、学的其实只是怎么用算法,对算法的正确性没有好好理解,或者说根本没有真的理解算法并从这个算法在做修改延伸;
2、学的很不系统,没有好好对比整理各种题型,更别说好好总结;
3、貌似整天参考别人代码,很少独立做题;
操,这种急功近利的学习方式终于可以在亚洲赛没机会现场赛的时候结束了,想来也是好事
不废话了,入正题
一、RMQ原理
DP思想:dp(i,j)=min(dp(i,j-1),dp(i+2^(j-1),j-1)) 这里dp(i,j)表示以i开头长度为2^(j)的区间内的最小值,同理求最大值。说白了还是二分思想,好广泛而牛逼的二分啊。
时间复杂度分析:初始化O(nlogn),查询O(1)
其实会了动规,应该自己能发明RMQ,为什么我们没想到呢?自己学算法到底只是学怎么用算法还是在学算法本身并从中有创造?值得反思......
原理不难,但是写模版问题还是比较多的...
1、数组开多大?怎么开?
2、查询怎么做?
看代码吧,我做了注释:
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 200001;
int a[N], d[20];
int st[N][20]; void ReadIn(const int &n)
{
int i;
for( i=0; i < n; ++i ) scanf("%d", &a[i]);
} inline int max(const int &arg1, const int &arg2)
{
return arg1 > arg2 ? arg1 : arg2;
} void InitRMQ(const int &n)
{
int i, j; for( d[0]=1, i=1; i < 21; ++i ) d[i] = 2*d[i-1];
for( i=0; i < n; ++i ) st[i][0] = a[i];
int k = int( log(double(n))/log(2.0) ) + 1;/*这里写log(2)的话,在poj会一直CE*/
for( j=1; j < k; ++j )
for( i=0; i < n; ++i )
{
if( i+d[j-1]-1 < n )
{
st[i][j] = max(st[i][j-1],st[i+d[j-1]][j-1]);
/*st数组的设计还是很不错的,省了很多空间,
st[i][j]指的是以a[i]开头的长度为2^j的区间的最小值,
这算是离散化的思想吗???以一个点代替一个区间*/
}
else break; // st[i][j] = st[i][j-1];
}
} void Query(const int &Q)
{
int i;
for( i=0; i < Q; ++i )
{
int x, y, k; // x, y均为下标:0...n-1
scanf("%d%d", &x, &y);
k = int( log(double(y-x+1))/log(2.0) );
printf("%d\n", max(st[x][k], st[y-d[k]+1][k]));
/*这里也很巧妙。另外,因为st[y-d[k]+1][k]写成st[y-d[k]][k]WA了无数次*/
}
} int main(void)
{
int n, Q; while( scanf("%d%d", &n, &Q) != EOF )
{
ReadIn(n); InitRMQ(n); Query(Q);
}
return 0;
}
对于POJ3368
http://poj.org/problem?id=3368
样例中
-1 -1 1 1 1 1 3 10 10 10
我处理为 2,4,1,3;
就是2个-1,4个1,1个3,3个10的意思;
另外开了几个数组:
v[ ]意思是原始的数组,存的-1 -1 1 1 1 1 3 10 10 10;
val[ ]就是存的 2,4,1,3;
left[i]=j,意思是元素i在原始 数组的下标为j;right[]同理;
pos[i]=num,值为i的元素在val数组的下标。
这样就可以把v[]华为RMQ的数组了;
查询的时候需要处理,ans=max(左边界的值出现的次数,右边界的值出现的次数,除去左右的区间中的次数的最大值)
左右的区间中的次数的最大值,这个用RMQ去算,左边界的值出现的次数,右边界的值出现的次数,需要每次查询自己处理。
注意边界啊,很能容易错
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 100005;
const int HASH = 100000; int st[N][20],val[N],left[N*2],right[N*2],v[N],pos[N*2],d[N]; void init(int n)
{
int k,i,j; k=(int)(log(double(n))/log(2.0))+1;
for(d[0]=1,i=1;i<21;i++)d[i]=2*d[i-1];
for(i=0;i<n;i++)st[i][0]=val[i];
for(j=1;j<k;j++)
{
for(i=0;i<n;i++)
if(i+d[j-1]-1<n)
st[i][j]=max(st[i][j-1],st[i+d[j-1]][j-1]);
else
break;
} } void query(int x,int y)
{
int l,r,a,b,ans;
a=v[x];
b=v[y];
if(pos[b+HASH]>=pos[a+HASH]+2)
{
r=right[a+HASH];
int k=(int)(log((double)(pos[b+HASH]-pos[a+HASH]-1))/log(2.0));
ans=max(r-x+1,st[pos[a+HASH]+1][k]);
l=left[b+HASH]; ans=max(ans,y-l+1);
ans=max(ans,st[pos[b+HASH]-d[k]][k]);
printf("%d\n",ans);
}
else
if(pos[b+HASH]==pos[a+HASH]+1)
{
r=right[a+HASH];
l=left[b+HASH];
printf("%d\n",max(r-x+1,y-l+1));
}
else {
printf("%d\n",y-x+1);
} } int main()
{
//freopen("poj 3368.txt","r",stdin);
int i,l,r,n,t,b,num,q; while(scanf("%d",&n)&&n)
{
memset(val,0,sizeof(val));
memset(st,0,sizeof(st));
scanf("%d",&q); scanf("%d",&b);
val[num=0]++;
left[b+HASH]=right[b+HASH]=0;
v[0]=b;
pos[b+HASH]=num;
for(i=1;i<n;i++)
{
scanf("%d",&t);
v[i]=t;
if(t==b)
{
val[num]++;
}
else
{
right[b+HASH]=i-1;
pos[b+HASH]=num;
b=t;
left[b+HASH]=i;
val[++num]++;
pos[b+HASH]=num;
}
} init(++num);
for(i=0;i<q;i++)
{
scanf("%d%d",&l,&r);
query(l-1,r-1);
}
} return 0;
}
POJ 3368 RMQ-ST的更多相关文章
- poj 3368(RMQ模板)
题目链接:http://poj.org/problem?id=3368 题意:给出n个数和Q个询问(l,r),对于每个询问求出(l,r)之间连续出现次数最多的次数. 求解RMQ问题的算法有:搜索(比较 ...
- POJ 3368/RMQ/线段数
题目链接 /* 给出一段序列,询问[L,R]区间内最大相同数的个数. 用一个很巧妙地方法,转化成求区间内的最大值的问题. RMQ维护区间最大值. MAX处理: */ for(int i=1;i< ...
- POJ 3368 (ST表)
链接:http://poj.org/problem?id=3368 题意:给出n个连续单调不递减数,q次询问,每次询问区间(L,R)出现频率最多的数,问出现了多少次 思路:因为n个数是单调不递减的,所 ...
- poj 3368 rmq ***
题意:给出n个数和Q个询问(l,r),对于每个询问求出(l,r)之间连续出现次数最多的次数. #include<cstdio> #include<iostream> #incl ...
- poj 3368 Frequent values(RMQ)
/************************************************************ 题目: Frequent values(poj 3368) 链接: http ...
- POJ 3368 Frequent values 线段树与RMQ解法
题意:给出n个数的非递减序列,进行q次查询.每次查询给出两个数a,b,求出第a个数到第b个数之间数字的最大频数. 如序列:-1 -1 1 1 1 1 2 2 3 第2个数到第5个数之间出现次数最多的是 ...
- POJ 3368 & UVA 11235 - Frequent values
题目链接:http://poj.org/problem?id=3368 RMQ应用题. 解题思路参考:http://blog.csdn.net/libin56842/article/details/4 ...
- hdu 3183 A Magic Lamp RMQ ST 坐标最小值
hdu 3183 A Magic Lamp RMQ ST 坐标最小值 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183 题目大意: 从给定的串中挑 ...
- NYOJ 119 士兵杀敌(三) RMQ ST
NYOJ 119 士兵杀敌(三) RMQ ST 题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=119 思路: ST在线 预处理O(nlog ...
随机推荐
- 是否需要手动执行DataContext的Dispose方法?
我们知道DataContext实现了IDisposable接口.在C#中,凡是实现了IDisposable接口的类,都推荐的使用using语句.如下: using (DataContext db = ...
- ###Android 断点调试和高级调试###
转自:http://www.2cto.com/kf/201506/408358.html 有人说Android 的调试是最坑的,那我只能说是你不会用而已,我可以说Android Studio的调试是我 ...
- EasyUI DataGrid定制默认属性名称
EasyUI DataGrid绑定服务器返回Json数据的解决方案 1. 服务器返回的数据对象格式,及初始化返回值 public class RequestResult { private int c ...
- 【点击模型学习笔记】Predicting Clicks_Estimating the Click-Through Rate for New Ads_MS_www2007
概要: 微软研究院的人写的文章,提出用逻辑回归来解决ctr预估问题,是以后ctr的经典解决方式,经典文章. 详细内容: 名词: CPC -- cost per click CTR -- click t ...
- 使用 AngularJS 和 ReactJS 的经验
1. React 福音 当我们的团队开始寻找一个合适的前端框架的时候,我们考虑了许多选择,最后留下两个选项 —— Angular 和 React. Angular 是目前为止最成熟的方案:它拥有一个庞 ...
- vnc远程linux服务器黑屏
本来想尝试用vnc连接到linux服务器上,图形化操作一点东西,不过遇到了困难,记录方便查询. 1,打开vnc 选择Ip和端口,连接上去显示黑屏. 2,于是想到系统原先没有安装图像化桌面.so, y ...
- MVC 笔记(二)
HttpUtility.HtmlEncode来预处理用户输入,这能阻止用户向视图中用链接注入js代码或html标记 .[Required]:非空验证 .[StringLength(**)]:设置字符的 ...
- ubuntu python PyCharm virtualenv
1.安装virtualenv 参照:http://docs.jinkan.org/docs/flask/installation.html 2.PyCharm结合virtualenv开发应用 PyCh ...
- [转载]Matlab中fft与fftshift命令的小结与分析
http://blog.sina.com.cn/s/blog_68f3a4510100qvp1.html 注:转载请注明出处——by author. 我们知道Fourier分析是信号处理里很重要的技术 ...
- 我们为什么要遵循W3C标准规范
大部分的站长和拥有网站的企业负责人都会知道,每当有浏览器发布大更新的时候,我们刚建立不久的网站就会发生无法预知的严重错误,我们只能重新建立或改版网站,使其可以应归新发布的浏览器.好比1996-1999 ...