ST表
ST算法(Sparse Table):
它是一种动态规划的方法。以最小值为例。a为所寻找的数组,用一个二维数组
f(i,j)记录区间[i,i+2^j-1]区间中的最小值。其中f[i,0] = a[i];所以,对于任意
的一组(i,j),f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)}来使用动态规划计算出来。
这个算法的高明之处不是在于这个动态规划的建立,而是它的查询:它的查询效
率是O(1)!如果不细想的话,怎么弄也是不会想到有O(1)的算法的。假设我们要求
区间[m,n]中a的最小值,找到一个数k使得2^k<n-m+1,即k=[ln(b-a+1)/ln(2)] 这样,
可以把这个区间分成两个部分:[m,m+2^k-1]和[n-2^k+1,n]!我们发现,这两个区间
是已经初始化好的!前面的区间是f(m,k),后面的区间是f(n-2^k+1,k)!这样,只要
看这两个区间的最小值,就可以知道整个区间的最小值!
小结:
稀疏表(SparseTable)算法是O(nlogn)-O(1)的,对于查询很多大的情况下比较好。
ST算法预处理:用dp[i,j]表示从i开始的,长度为2^j 的区间的RMQ,则有递推式dp[i,j]=min{dp[i,j-1],dp[i+2j-1,j-1]}即用两个相邻的长度为2j-1的块,更新长度为2j的块。因此,预处理时间复杂度为O(nlogn)。这个算法记录了所有长度形如2k的所有询问的结果。从这里可以看出,稀疏表算法的空间复杂度为 O(nlogn)。
代码:
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; int n,a[1001],f[1001][20]; int rmq(int x,int y) { int k=floor(log(double(y-x+1)/log(2.0))); return min(f[x][k],f[y-(1<<k)+1][k]); } int main() { int i,j; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]),f[i][0]=a[i]; int k=floor(log(double(n)/log(2.0))); for(j=1;j<=k;j++) for(i=n;i>=1;i--) if(i+(1<<(j-1))<=n) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); int x,y; scanf("%d%d",&x,&y); printf("%d",rmq(x,y)); return 0; }