·【蓝桥】晚会节目单(ST表)

题目来源(优秀博客):https://blog.csdn.net/qq_43746332/article/details/105145456
人家用线段树我可玩不来,先学好ST表吧

题目分析
不改变节目顺序,每次都希望好看值value最大,并不是总的value最大
因此n组节目中选择m次的原始做法应是:
尺取法开始front=0, tail=n-m 在[front, tail]区间内查找value最大值,记录下标ans,更新front,tail
接着front=ans+1, ++tail 查询m次数即可,复杂度O(n^2),优化方法ST表,复杂度O(n*logn)

算法思想
ST表可在多次查询区间最值时将复杂度降至 O(n*logn)
关于ST表详细构建可参考我的: https://www.weayer.top/2020/03/28/Dp-ST/
这里稍微不同的是不仅要求得区间[l,r]的最大值,关键要记录下标(因为尺取的需要)
所以ST表的预处理、查询均稍作修改
原dp转移方程:

dp[i][j]=max(dp[i][j-1], dp[i+2^(j-1)][j-1])

现dp转移方程:

int ans1 = dp[i][j-1];
int ans2 = dp[i+pow_(j-1)][j-1];
dp[i][j] = a[ans1]>=a[ans2] ? ans1: ans2;

原查询操作:

int k = log2(r-l+1.0);
return max(dp[l][k], dp[r-2^k+1][k]);
现查询操作:
int k = log2(r-l+1.0);
int ans1 = dp[l][k];
int ans2 = dp[r-2^k+1][k];
return a[ans1]>=a[ans2] ? ans1: ans2;

——————————————完整代码————————————————

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
int a[100005];
int dp[100005][25];
int m, n;
int pow_(int x)
{
return 1 << x;
}
void ST()
{
for(int i = 0; i < m; ++i)
dp[i][0] = i; //不同的是,dp记录最值的下标
for(int j = 1; pow_(j) < m; ++j)
{
for(int i = 0; i+pow_(j-1) < m; ++i)
{
int ans1 = dp[i][j-1];
int ans2 = dp[i+pow_(j-1)][j-1];
dp[i][j] = a[ans1]>=a[ans2] ? ans1: ans2;
}
}
}
int solve(int l, int r)
{
int k = log2(r-l+1.0);
int ans1 = dp[l][k];
int ans2 = dp[r-pow_(k)+1][k];
return a[ans1]>=a[ans2] ? ans1: ans2;
}
int main()
{
cin >> m>> n;
for(int i = 0; i < m; ++i)
cin >> a[i];
int front = 0, tail = m-n, k = 0;
ST();
// for(;;)
// {
// int x, y;
// cin >> x >> y;
// cout << solve(x, y) <<endl;
// }
while(tail<m && front<=tail) //尺取法,查找n次
{
int ans = solve(front, tail);
cout << a[ans] <<" ";
front = ans+1;
tail++;
}
printf("\n");
return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!