乗算とSTアルゴリズム

倍増

これは乗算であり、毎回2を乗算するのと同じであることが理解しやすいため、乗算は通常、バイナリビット演算に関連付けることができます。掛け算法の特徴は、1、2、4 、…、2 k 1、2、4、…、2 ^ kを事前に計算する必要があることです。1 2 4 2Kスプリングボード、これにはデータが静的で動的ではないことが必要です。データが変更された場合、すべてのスプリングボードを再計算する必要があり、スプリングボードは無意味です。
   乗算法の古典的なアプリケーションは、行列高速電力、接尾辞配列、STアルゴリズム、LCA(最も近い共通の祖先)です。このセクションでは、比較的単純なSTアルゴリズムを紹介し、乗算を適用するという古典的な問題も示します。

STアルゴリズム

STアルゴリズムは、主に静的RMQ問題、つまり、値を変更せずに最大および最小アクセス間隔を解決します。主なアイデアは、広い領域で最良の値を見つけ、小さな領域を大きな領域にマージすることです。結果は、分離された領域の中で最良の値になり、結果を見つけます。たとえば、少し複雑です。

要求1-20,那么我们可以分解成 min(或max)(dp[1][16],dp[17][20]);
能分解成min(或max)(dp[1][16],dp[17][20]); 这样当然也就是可以分解成这样:
min(或max)(dp[1][16],dp[20-16+1][20]);
就是有重复的,因为我们要求的最值所以重复不会影响结果。
dp[i][j]表示i到j存的最小/大值。
为什么是16那?不可以是10,14,15吗?
当然可以只不过用16会更优化 因为16是2的倍数,那么我们就可以引入倍增了。
ST思想:
 (1)把整个数列分为很多小区间,并提前计算出每个小区间的最值;
 (2)对任意一个区间最值查询,找到覆盖它的两个小区间,用两个小区间的最值算出答案。

さんの写真を使うのはいいことですが、もちろん羅さんの方が上手く書いています。
まず、間隔に格納されている最大値であるST配列を最初に作成します。間隔の長さは最大値の1です。前に、乗算は踏み台として機能すると述べたので、2 0 2 ^ 0から開始できます20ジャンプして21 2 ^ 121(つまり、動的計画法の考え方を使用して、21は2つに均等に分割されます)これは、2 1 2 ^ 1の間隔の長さです21の最大値。これにより、2 2 2 ^ 2にジャンプできます。22

ジャンプできなくなるまで(1 << k)>ジャンプできなくなるまで、元の配列の長さより長くなります。

ここに画像の説明を挿入します
したがって、再帰式を見つけることができます。
dp[l][k]=max(dp[l][ k - 1],dp[ r - 1<<( k - 1) + 1][ k - 1 ]);
長さは1 <<(k − 1)1 <<(k-1)1<<k1 終点はrrですrの開始点はr-1 <<(k-r1<<k1 +1
lllは左のエンドポイント、kkですkは、2進数の数、つまり長さ(2のk乗)です。rrrは正しいエンドポイントです。

P2880USACO07JANBバランスラインナップG

別の日を説明する

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;

ll n,m;
ll d[50010][100],p[50001][100];
ll a[maxn],b[100];

int main() {
    
    
    scanf("%lld%lld",&n,&m);
    for(int i=1; i<=n; i++)scanf("%lld",&a[i]),d[i][0]=p[i][0]=a[i];
    b[0]=1;
    ll flag=0;
    for(int i=1; i<64; i++) {
    
    
        b[i]=b[i-1]*2;
        if(b[i]>=n) {
    
    
            flag=i;
            break;
        }
    }

    for(int i=1; i<=flag; i++) {
    
    
        for(int j=1;j<=n-b[i]+1;j++){
    
    
            d[j][i]=min(d[j][i-1],d[j+b[i-1]][i-1]);
            p[j][i]=max(p[j][i-1],p[j+b[i-1]][i-1]);
        }
    }

    while(m--) {
    
    
        ll l,r;
        scanf("%lld%lld",&l,&r);
        ll len=r-l+1;
        ll k;
        for(int i=0;i<=flag;i++){
    
    
            if(b[i]<=len){
    
    
                k=i;
            }else break;
        }
        ll minn=min(d[l][k],d[r-b[k]+1][k]);
        ll maxx=max(p[l][k],p[r-b[k]+1][k]);
        printf("%lld\n",maxx-minn);
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/weixin_45911397/article/details/111085611