P1714切蛋糕(不定区间最值)
Posted iss-ue
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1714切蛋糕(不定区间最值)相关的知识,希望对你有一定的参考价值。
题面
今天是小Z的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值。
小Z作为寿星,自然希望吃到的第一块蛋糕的幸运值总和最大,但小Z最多又只能吃M小块(M≤N)的蛋糕。
吃东西自然就不想思考了,于是小Z把这个任务扔给了学OI的你,请你帮他从这N小块中找出连续的k块蛋糕(k≤M),使得其上的幸运值最大。
不定区间长度还是第一次遇到
分析 考虑朴素写法,非常直观。
对于以第i个元素结尾的子段,最大的子段和P(i)可以表示为
P [ i ] = max { sum [ i ] - sum [ j ] , j 属于 [ i-M, i-1 ]
于是有ans = max [ P [ i ] ]
算法的复杂度是O ( N M )
在题目的范围下TLE是必然的
将上面P[i]的计算式改写为
P [ i ] = sum [ i ] - min { sum [ j ] },j属于 [ i-M , i-1 ]
显然,在每次获取 P [ i ] 的时候,Sum [ i ] 是定值,所以 P [ i ] 由 Sum [ j ] 的最小值确定。
于是我们就要想方设法在优于O(M)的时间内实现获取最小的 Sum [ j ] 。
最优时,Sum [ j ] 的性质:
(1)Sum [ j ] ≤ Sum [ x ] x∈ [ i-M , i-1 ]且x≠j
(2)j∈[ i-M , i-1 ]
枚举加优化
考虑设计这样一个数据结构,在更低的时间复杂度内获取最优Sum [ j ] 。
①单调队列
#include <iostream> using namespace std; #define max(a,b) (a>b?a:b) const int maxn=500009; int a[maxn],zhui[maxn]; int q[maxn],p[maxn],ans=-9999999,spfa[maxn]; int main() { int n,m,tail=0,head=1; cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; zhui[i]=zhui[i-1]+a[i]; } for(int i=1;i<=n;i++) { while(tail>=head&&q[tail]>=zhui[i]) tail--; q[++tail]=zhui[i];p[tail]=i; while(p[head]+m<=i) head++; spfa[i]=q[head]; } for(int i=1;i<=n;i++) ans=max(ans,zhui[i]-spfa[i-1]); cout<<ans; }
②ST稀疏表
#include <bits/stdc++.h> using namespace std; const int maxn=500009; int a[maxn],zhui[maxn]; int ans=-9999999,dis[maxn][22]; int query(int l,int r){ int k=log2(r-l+1); return min(dis[l][k],dis[r+1-(1<<k)][k]); } int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) { int t; cin>>t; zhui[i]=zhui[i-1]+t; dis[i][0]=zhui[i]; } for(int j=1;j<=log2(n);j++) { for(int i=1;i+(1<<j)-1<=n;i++) dis[i][j]=min(dis[i][j-1],dis[i+(1<<(j-1))][j-1]); } for(int i=1;i<=n;i++) { int l=i-m;//等于是求i-m+1到第i项 if(l<0) l=0; ans=max(ans,zhui[i]-query(l,i)); } cout<<ans; }
以上是关于P1714切蛋糕(不定区间最值)的主要内容,如果未能解决你的问题,请参考以下文章