参考资料:https://blog.csdn.net/niushuai666/article/details/6624672
题意:
给定n头牛和q个区间,以及每头牛的身高,求每个给定区间内最高的牛和最矮的牛高度的差值。
RMQ算法:
RMQ(Range Minimum/Maximum Query),也就是区间最值查询。
RMQ的主要思想:
1.预处理,利用动态规划,理解状态转移方程。
dp[i][j]代表的是从第i个数开始,连续的2^j个数中的最大(小)值。
显然,如果j==0,那么这个最大值就是第i个数本身。于是,我们得到初值条件:dp[i][0]=a[i]
接着,我们开始状态转移。我们不妨让它平分成两段。
平分的原理:dp[i][j]代表的是(i,i+2^j)这个整个长度是(i+i+2^j)/2 = i+2^(j-1)
据此,我们可以得到两段(i,i+2^(j-1))和(i+2^(j-1),j)
于是,我们得到状态转移方程:dp[i][j]=max(dp[i][j-1], dp[i + 2^(j-1)][j-1])
核心代码:
void RMQ(int num)
{
for(int i=1;i<=n;i++)
{
dpMAX[i][0]=b[i];
dpMIN[i][0]=b[i];
}
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
{
dpMAX[i][j]=max(dpMAX[i][j-1],dpMAX[i+(1<<(j-1))][j-1]);
dpMIN[i][j]=min(dpMIN[i][j-1],dpMIN[i+(1<<(j-1))][j-1]);
}
}
2.查询
比如给定区间(i,j)
这个区间的长度为j - i + 1,我们可以取k=lg( j - i + 1)/lg 2,然后查询(i,k)和(k,j)
核心代码:
int rmqMAX(int s,int v)
{
int k=(int)(log(v-s+1.0)/log(2.0));
return max(dpMAX[s][k],dpMAX[v-(1<<k)+1][k]);
}
解题思路:
0.输入数据,注意数组利用全局变量处理
1.写RMQ函数和RMQ查询函数,直接套用,查询最大值和最小值
2.将最大值和最小值作差输出即可
关键:
理解RMQ中的位运算的操作。n<<k代表的是 n * 2^k