九度1544

刚学的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>






你可能感兴趣的:(优化,dp,动态规划,ST算法)