洛谷:P2880 [USACO07JAN]Balanced Lineup G(倍增,普及/提高-)

题目:

洛谷:P2880 [USACO07JAN]Balanced Lineup G(倍增,普及/提高-)_第1张图片

分析:洛谷:P2880 [USACO07JAN]Balanced Lineup G(倍增,普及/提高-)_第2张图片

为什么要倍增?一方面是节省数组,另一方面状态转移的也快了,因为需要的状态都少了,

不倍增时,f【2,8】=max(f【2,7】,A【2+8】)。

2的多少次方应该想到移位运算的啊!

先看ac代码的结构:

洛谷:P2880 [USACO07JAN]Balanced Lineup G(倍增,普及/提高-)_第3张图片

其相当于独立的n个问题进行的求解,即使两次数据相同,也要再重新完完全全的算一遍。不是,是先算出来几乎全部,具体情况再处理。

很明显的一个递推,自己非要写成递归。

当具体问题时,我想的利用2的次方的性质,从大向小加,因为2的次方总能拼成任何的数字。具体为:

洛谷:P2880 [USACO07JAN]Balanced Lineup G(倍增,普及/提高-)_第4张图片

而题解这样不是更简单吗?

洛谷:P2880 [USACO07JAN]Balanced Lineup G(倍增,普及/提高-)_第5张图片

有重复无所谓呀,自己还是太菜。

全抄代码:

#include
using namespace std;
int A1[50005][20];//最大
int A2[50005][20];//最小
int A[50005];
void work1(int n) 
{
     
    for ( int i=1;i<=n;i++) A1[i][0]=A[i];
    for (int j=1;(1<<j)<=n;j++) 
        for (int i=1;i+(1<<j)-1<=n;i++) 
            A1[i][j]=max(A1[i][j-1],A1[i+(1<<(j-1))][j - 1]);
}
void work2(int n) 
{
     
    for (int i=1;i<=n;i++) A2[i][0]=A[i];
    for (int j=1;(1<<j)<=n;j++) 
        for (int i=1;i+(1<<j)-1<=n;i++) 
            A2[i][j]=min(A2[i][j-1],A2[i+(1<<(j-1))][j - 1]);
}
int RMQ(int l, int r) 
{
     
    int k=0;
    while ((1<<(k+1))<=r-l+1)
         k++;
    return max(A1[l][k],A1[r-(1<<k)+1][k]);
}
int RMQ2(int l, int r) 
{
     
    int k=0;
    while ((1<<(k+1))<=r-l+1)
         k++;
    return min(A2[l][k],A2[r-(1<<k)+1][k]);
}
int main()
{
     
 //读入 
 int m,n;
 cin>>m>>n;
 for(int i=1;i<=m;i++) cin>>A[i];
 work1(m);
 work2(m);
 for(int ii=0;ii<n;ii++)
 {
     
  int x,y;
  cin>>x>>y;
  cout<<RMQ(x,y)-RMQ2(x,y)<<endl;
  } 
} 

你可能感兴趣的:(我认为的精华,动态规划,倍增)