【DP专题】——jzoj 6305. 最小值

Description

 

Input

Output

 

Sample Input

Sample 1:
5 0 0 1 10
9 9 5 2 6 

Sample 2:
100 1 1 1 1
18515 13638 5356 485 8646 14871 18955 6206 7630 14703 
6786 15099 15960 17822 435 3233 9775 20340 12669 14079
1164 3329 3642 16094 4294 2462 18926 16887 17661 8416
18196 20799 15422 1943 13795 11165 21418 5646 7773 11921
14908 9305 3334 13677 5757 6875 15324 20940 10919 7703
14804 19536 13777 3500 4797 6658 19839 2962 19871 2668 16584
19193 13887 20172 5323 11400 3381 14167 11494 14646 682 2333
11615 16430 6959 14652 19819 13504 20629 1202 17839 13863
4646 3607 14270 10575 6024 3583 16544
11898 1395 18535 12607 6929 736 2303 8950 20436 7050  

Sample Output

Sample 1:
81

Sample 2:
263138765928780
 
 

Data Constraint

不想吐槽这个排版了……

首先写出动规方程:

 

考虑维护一下,

 

发现当没有找到一个更小的值时,包含已发现的最小值的区间取值相同,这个时候无论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 }

感谢纪中小伙伴提供的解法指导。

 

posted @ 2019-08-17 20:26  Nelson992770019  阅读(259)  评论(0编辑  收藏  举报