刚学的st算法,顺便看到了lg取下届的数组实现方式,以前没用过lg这东西,这里存下,关于st算法,本质是动态规划,个人dp认为主要注意的是三点,1初始值,2边界,3递推顺序,方程是这样的:
最大值 dp[i,j]=max(dp[i,j-1],dp[i+2^(j-1),j-1]);,
最小值 dp[i,j]=min(dp[i,j-1],dp[i+2^(j-1),j-1]);
dp[i][j]表示的是以i为起始点,一共2^j次个数的最值 ,比如dp[i][0]表示i这个数,dp[i][1]表示i,i+1这2个数的最值且dp[i,0]其实就等于a[i],这样就可以推出所有的dp[i,j]了,另外一个问题是,要你求(x,y)区间的最值,如何用dp数组把他们求出来呢,可能很多情况下,我们找不到正好的dp,那么我们找有重复的也可以,比如我要求3到8区间的最小值,那么我分成(3,6),(5,8)你会发现5,6这2个数算了2次,但是对于求最值来说,这无所谓,只要我能找到两个区间(长度是2的i次的),把头和尾盖住(注意不能小于头,也不能大于尾),但是中间那段重复是没关系的,就好,一般的处理是
tmp=lg[y-x+1];
取 dp[x][tmp],dp[y-(1<<tmp)+1][tmp] 这2个的最值。
附九度oj1544代码如下:
<span style="font-size:18px">#include<stdio.h> int a[1000001]; int lg[100001]; int dp[1000001][25]; int min(int x,int y) { return x<y?x:y; } int solve(int x,int y) { int tmp=lg[y-x+1]; return min(dp[x][tmp],dp[y-(1<<tmp)+1][tmp]); } int main() { int n; lg[0]=-1; for(int i=1;i<=100000;i++) lg[i]=lg[i/2]+1; while(scanf("%d",&n)!=EOF) { int i,j; for(i=1;i<=n;i++) { scanf("%d",a+i); dp[i][0]=a[i]; } for(i=1;(1<<i)<=n;i++) for(j=1;j+(1<<i)-1<=n;j++) dp[j][i]=min(dp[j][i-1],dp[j+(1<<(i-1))][i-1]); int m; scanf("%d",&m); for(i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); printf("%d\n",solve(a,b)); } } return 0; }</span>