dp+单调栈
6305. 最小值
(File IO): input:min.in output:min.out
Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits
Goto ProblemSet不想吐槽这个排版了……
首先写出动规方程:
考虑维护一下,
发现当没有找到一个更小的值时,包含已发现的最小值的区间取值相同,这个时候无论dpj放哪个位置,dpi的值只与dpj有关,考虑转移的特性,我们让dpj最大,就可以为答案做出更大贡献。
单调栈:
单调栈即满足单调性的栈结构。与单调队列相比,其只在一端进行进出。 ——OI WIKI
考虑用单调栈维护,当我们发现一个新的min值时,我们需要更新栈中的值,因为新的min值可能使答案更优。
具体实现:
- 我们创建一个单调下降的栈。
- 当我们遇到一个小于等于栈顶的值时,设这个值为a[i],则显然,所以可以tail--,找到最大的dp[j]。
- 如果此时栈里还有值,说明这个值比当前值还要小,就要再进行比较,看能否找到更优解。
- 最后更新dp[i]=dp[j]+f(a[i])。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll inf=1e14; 5 const ll N=2e5+10; 6 ll n,A,B,C,D; 7 ll a[N],dp[N]; 8 ll f(ll x){ 9 return A*x*x*x+B*x*x+C*x+D; 10 } 11 ll read(){ 12 ll x=0,f=1; 13 char c=getchar(); 14 while(!isdigit(c)){ 15 if(c=='-') f=-1; 16 c=getchar(); 17 } 18 while(isdigit(c)){ 19 x=x*10+c-'0'; 20 c=getchar(); 21 } 22 x*=f; 23 return x; 24 } 25 struct stack{ 26 ll str[N],tail,strpos[N],ans[N]; 27 inline ll pos(ll i){ 28 return strpos[i]; 29 } 30 inline ll v(ll i){ 31 return str[i]; 32 } 33 }s; 34 ll idx[N],num[N]; 35 int main(){ 36 freopen("min.in","r",stdin); 37 freopen("min.out","w",stdout); 38 scanf("%lld%lld%lld%lld%lld",&n,&A,&B,&C,&D); 39 for(register int i=1;i<=n;i++){ 40 scanf("%lld",&a[i]); 41 } 42 s.tail=0; 43 for(register int i=1;i<=n;i++){ 44 ll tmp=dp[i-1]; 45 while(s.tail>0&&a[s.pos(s.tail)]>=a[i]){ 46 tmp=max(tmp,s.v(s.tail)); 47 s.tail--; 48 } 49 s.strpos[++s.tail]=i; 50 s.str[s.tail]=tmp; 51 if(s.tail>1){ 52 s.ans[s.tail]=max(tmp+f(a[i]),s.ans[s.tail-1]); 53 } 54 else s.ans[s.tail]=tmp+f(a[i]); 55 dp[i]=s.ans[s.tail]; 56 } 57 printf("%lld",dp[n]); 58 return 0; 59 }
感谢纪中小伙伴提供的解法指导。