【杂题】【动态规划】——jzoj 6305. 最小值

二次信任 提交于 2019-11-27 16:28:27

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 }

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

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!