POJ3264 MRQ算法

poj 3264

给n个数,求任意区间内的最值差。

思路: n l o g n nlogn nlogn 的 算法在这里可以过,有线段树和RMQ算法两种。这里介绍RMQ算法。

RMQ算法是位运算动态规划算法,定义dp[i][j] 为 [ i , i + 2 j − 1 ] [i,i+2^j -1] [i,i+2j1] 区间内的最值。那么该区间可以划分为两个相同大小的区间 [ i , i + 2 j − 1 − 1 ] [i,i+2^{j-1}-1] [i,i+2j11] [ i + 2 j − 1 , i + 2 j − 1 ] [i+2^{j-1},i+2^j-1] [i+2j1,i+2j1]

这两个区间用dp数组表示就是 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j1], d p [ i + 2 j − 1 ] [ j − 1 ] dp[i+2^{j-1}][j-1] dp[i+2j1][j1]

所以状态转移方程:mm[i][j]=max/min(mm[i][j-1],mm[i+(1<<(j-1))][j-1]);

                mm[i][0]=a[i];

查询[l,r]区间内的时候就找到一个k, ( i n t ) k = l o g 2 ( r − l + 1 ) (int)k=log_2(r-l+1) (int)k=log2(rl+1) ,目的在于找到[l,r]的一个覆盖,两个区间覆盖[l,r],可以相交。这两个区间长度不超过r-l+1,并且是2的幂。这样子就可以用dp[l][k],dp[r-(1<<k)+1][k] 表示[l,r]区间内最值。

void rmq_init(int n)
{
    for(int i=1; i<=n; i++)
    {
        mm[i][0]=mi[i][0]=a[i];
    }
    for(int j=1; (1<<j)<=n; j++)
    {
        for(int i=1; i+(1<<j)-1<=n; i++)
        {
            mm[i][j]=max(mm[i][j-1],mm[i+(1<<(j-1))][j-1]);
            mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
        }
    }
}
void rmq(int l,int r)
{
    int len=r-l+1;
    int k=(int)(log(r-l+1.0)/log(2.0));
    int ans1=max(mm[l][k],mm[r-(1<<k)+1][k]);
    int ans2=min(mi[l][k],mi[r-(1<<k)+1][k]);
}

上面是模板。

对于这个题目来说模板是刚好的。注意的是不要用cin输入,会超时,哪怕使用ios::sync_with_stdio(false)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define maxn 50000+10
using namespace std;

int mm[maxn][100];
int mi[maxn][100];
int a[maxn];
void rmq_init(int n)
{
    for(int i=1; i<=n; i++)
    {
        mm[i][0]=mi[i][0]=a[i];
    }
    for(int j=1; (1<<j)<=n; j++)
    {
        for(int i=1; i+(1<<j)-1<=n; i++)
        {
            mm[i][j]=max(mm[i][j-1],mm[i+(1<<(j-1))][j-1]);
            mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
        }
    }
}
int rmq(int l,int r)
{
    int len=r-l+1;
    int k=(int)(log(r-l+1.0)/log(2.0));
    int ans1=max(mm[l][k],mm[r-(1<<k)+1][k]);
    int ans2=min(mi[l][k],mi[r-(1<<k)+1][k]);
    return ans1-ans2;
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2)
    {
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        rmq_init(n);
        int lef,righ;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&lef,&righ);
            printf("%d\n",rmq(lef,righ));
        }
    }
    return 0;
}

非线性最小二乘法数据拟合算法实现 Private Sub Command1_Click() 'PROGRAM D9R8A 'Driver for routine MRQMIN NPT = 100 MA = 6 SPREAD = 0.001 Dim X(100), Y(100), SIG(100), A(6), LISTA(6) Dim COVAR(6, 6), ALPHA(6, 6), GUES(6) A(1) = 5#: A(2) = 2#: A(3) = 3#: A(4) = 2#: A(5) = 5#: A(6) = 3# GUES(1) = 4.5: GUES(2) = 2.2: GUES(3) = 2.8 GUES(4) = 2.5: GUES(5) = 4.9: GUES(6) = 2.8 IDUM& = -911 'First try a sum of two Gaussians For I = 1 To 100 X(I) = 0.1 * I Y(I) = 0# For J = 1 To 4 Step 3 Y(I) = Y(I) + A(J) * Exp(-((X(I) - A(J + 1)) / A(J + 2)) ^ 2) Next J Y(I) = Y(I) * (1# + SPREAD * GASDEV(IDUM&)) SIG(I) = SPREAD * Y(I) Next I MFIT = MA For I = 1 To MFIT LISTA(I) = I Next I ALAMDA = -1 For I = 1 To MA A(I) = GUES(I) Next I Call MRQMIN(X(), Y(), SIG(), NPT, A(), MA, LISTA(), MFIT, COVAR(), ALPHA(), MA, CHISQ, ALAMDA) K = 1 ITST = 0 1 Print "Iteration #"; K; "Chi-squared: "; Print Format$(CHISQ, "#####.##00"); Print " ALAMDA: "; Format$(ALAMDA, ".##E+00") Print Tab(5) Print Tab(3); "A(1) A(2) A(3) A(4) A(5) A(6)" For I = 1 To MA Print Format$(A(I), "#.###0"), Next I Print Tab(5) K = K + 1 OCHISQ = CHISQ Call MRQMIN(X(), Y(), SIG(), NPT, A(), MA, LISTA(), MFIT, COVAR(), ALPHA(), MA, CHISQ, ALAMDA) If CHISQ > OCHISQ Then ITST = 0 ElseIf Abs(OCHISQ - CHISQ) < 0.1 Then ITST = ITST + 1 End If If ITST < 2 Then GoTo 1 End If ALAMDA = 0# Call MRQMIN(X(), Y(), SIG(), NPT, A(), MA, LISTA(), MFIT, COVAR(), ALPHA(), MA, CHISQ, ALAMDA) Print Tab(5); "Uncertainties:" For I = 1 To MA Print Format$(Sqr(COVAR(I, I)), "#.###0"), Next I Print Tab(5); "Expected results:" Print Tab(2); "5.0 2.0 3.0 2.0 5.0 3.0" End Sub
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值