zoukankan      html  css  js  c++  java
  • POJ 3264 Balanced Lineup (RMQ分析)

    链接:http://poj.org/problem?id=3264

    RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。

    动态规划:

    设data[i]是要求最大值的数列。dp[i][j]表示以第i个数开始,长度为2^j段的最大值。 若将该段从中间分开(因为是2^j,肯定能分成两段),得到的子序列为 i~2^(j-1)-1 i+2^(j-1)~i+2^j-1。。写成方程的形式,即为:

    dp[i][j]=strcat( dp[i][j-1] , dp[i+2^[j-1]][j-1] )  //strcat()为字符串连接函数

    So....状态转移方程为:dp[i][j]=MAX( dp[i][j-1] , dp[i+2^[j-1]][j-1] ) ;

    dp[i][0]为它本身

    以下摘自:http://blog.csdn.net/niushuai666/article/details/7401403

    代码为:

    void RMQ(int num) //预处理->O(nlogn)
    {
    	for(int j = 1; j < 20; ++j)
    		for(int i = 1; i <= num; ++i)
    			if(i + (1 << j) - 1 <= num)
    			{
    				maxsum[i][j] = max(maxsum[i][j - 1], maxsum[i + (1 << (j - 1))][j - 1]);
    				minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 << (j - 1))][j - 1]);
    			}
    }

    其中1<<j为2^j

     

    这里我们需要注意的是循环的顺序,我们发现外层是j,内层所i,这是为什么呢?可以是i在外,j在内吗?


    答案是不可以。因为我们需要理解这个状态转移方程的意义。

    状态转移方程的含义是:先更新所有长度为F[i,0]即1个元素,然后通过2个1个元素的最值,获得所有长度为F[i,1]即2个元素的最值,然后再通过2个2个元素的最值,获得所有长度为F[i,2]即4个元素的最值,以此类推更新所有长度的最值。

    而如果是i在外,j在内的话,我们更新的顺序就是F[1,0],F[1,1],F[1,2],F[1,3],表示更新从1开始1个元素,2个元素,4个元素,8个元素(A[0],A[1],....A[7])的最值,这里F[1,3] = max(max(A[0],A[1],A[2],A[3]),max(A[4],A[5],A[6],A[7]))的值,但是我们根本没有计算max(A[0],A[1],A[2],A[3])和max(A[4],A[5],A[6],A[7]),所以这样的方法肯定是错误的。


    为了避免这样的错误,一定要好好理解这个状态转移方程所代表的含义。



    (二)然后是查询。

    假如我们需要查询的区间为(i,j),那么我们需要找到覆盖这个闭区间(左边界取i,右边界取j)的最小幂(可以重复,比如查询5,6,7,8,9,我们可以查询5678和6789)。

    因为这个区间的长度为j - i + 1,所以我们可以取k=log2( j - i + 1),则有:RMQ(A, i, j)=max{F[i , k], F[ j - 2 ^ k + 1, k]}。

    举例说明,要求区间[2,8]的最大值,k = log2(8 - 2 + 1)= 2,即求max(F[2, 2],F[8 - 2 ^ 2 + 1, 2]) = max(F[2, 2],F[5, 2]);


    在这里我们也需要注意一个地方,就是<<运算符和+-运算符的优先级。

    比如这个表达式:5 - 1 << 2是多少?


    答案是:4 * 2 * 2 = 16。所以我们要写成5 - (1 << 2)才是5-1 * 2 * 2 = 1。

     

     

     

    代码:

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    const int N = 50005;
    int dpmax[N][20], dpmin[N][20];
    
    void RMQ(int n)
    {
    	for(int j = 1; j != 20; j++)
    		for(int i = 1; i <= n; i++)	
    			if(i + (1 << j) - 1 <= n)					//i+2^j
    			{
    				dpmax[i][j] = max(dpmax[i][j - 1], dpmax[i + (1 << (j - 1))][j - 1]);			// i+2^(j-1)
    				dpmin[i][j] = min(dpmin[i][j - 1], dpmin[i + (1 << (j - 1))][j - 1]);
    			}
    		
    	
    }
    
    int main()
    {
    	int num, query;
    	int a, b;
    	while(scanf("%d %d", &num, &query) != EOF)
    	{
    		for(int i = 1; i <= num; ++i)
    		{
    			scanf("%d", &dpmax[i][0]);
    			dpmin[i][0] = dpmax[i][0];
    		}
    		RMQ(num);
    		while(query--)
    		{
    			scanf("%d%d", &a, &b);
    			int k = (int)(log(b - a + 1.0) / log(2.0));				//log2(b-a+1)....换底公式
    			int maxsum = max(dpmax[a][k], dpmax[b - (1 << k) + 1][k]);
    			int minsum = min(dpmin[a][k], dpmin[b - (1 << k) + 1][k]);
    			printf("%d
    ", maxsum - minsum);
    		}
    	}
    	return 0;
    }


     

     

     

  • 相关阅读:
    下载到99.5卡顿问题定位结论
    http的get方式和post方式
    广播中等待较久出现anr问题
    eclipse运行时出现Unable to execute dex
    Android系统切换语言更新应用界面方法
    Android进程退出的方法
    杀掉顽固的android进程
    dialog屏蔽back键的方法
    操作中按了home键后广播为什么接收不了问题
    oc nil Nil
  • 原文地址:https://www.cnblogs.com/frankM/p/4399526.html
Copyright © 2011-2022 走看看