zoukankan      html  css  js  c++  java
  • [ACM]初识斜率优化DP

    刚刚接触斜率优化DP,做了几道比较基础的题,算是稍微有些理解了。

    斜率优化DP的资料很多,最经典的资料还是周源04年OI论文《浅谈数形结合思想在信息学竞赛中的应用》,初学可以看它,进阶的话可以再去看看杨哲的《凸完全单调性的一个加强与应用》,做题可以搜题解。

    几点学习心得:

    1.动态规划时间复杂度:阶段*状态*决策所需时间。阶段*状态一般可视为状态总数,一般状态总数是确定的,我们无法减少它的遍历。那么,斜率优化DP就是在决策前通过维护策略的单调性减少状态数,降低一次决策所需的时间,从而降低时间复杂度。单调性如何维护由如何决策而定。

    2.斜率优化DP一般需要先写出容易想到的状态转移方程,然后列举2个子状态发现是否对后续状态有单调性。

    3.斜率优化DP一般通过单调队列维护状态,数形结合有助于解题,一般维护状态的单调性就是在2维坐标系中维护下凸折线。

    4.需要参与决策的状态才能够入队,否则不要加入队列,或延迟加入它。特别注意新加入状态斜率与队尾最后2个状态斜率相等的情况,舍取要看题意。

    列3道基础斜率优化DP题:

    1.HDU 3507 Print Article

    View Code
     1 #include<cstdio>
     2 #define maxn 500005
     3 typedef long long ll;
     4 long long   dp[maxn];
     5 ll sum[maxn];
     6 struct str
     7 {
     8     ll y,x;
     9 };
    10 str que[maxn];
    11 int main()
    12 {
    13     int n,m;
    14     dp[0]=sum[0]=0;
    15     while(~scanf("%d%d",&n,&m))
    16     {
    17         int head=0,tail=0;
    18         que[0].x=que[0].y=0;
    19         for(int i=1;i<=n;i++){scanf("%I64d",&sum[i]);sum[i]+=sum[i-1];}
    20         for(int i=1;i<=n;i++)
    21         {
    22             while(tail>head)
    23             {
    24                 str h1=que[head],h2=que[head+1];
    25                 if(h2.y-h1.y<2*(h2.x-h1.x)*sum[i])head++;
    26                 else break;
    27             }
    28             dp[i]=que[head].y+sum[i]*sum[i]-2*que[head].x*sum[i]+m;
    29             str ns;ns.x=sum[i];ns.y=dp[i]+sum[i]*sum[i];
    30             while(tail>head)
    31             {
    32                 str h1=que[tail],h2=que[tail-1];
    33                 if((ns.y-h1.y)*(h1.x-h2.x)<=(h1.y-h2.y)*(ns.x-h1.x))tail--;
    34                 else break;
    35             }
    36             que[++tail]=ns;
    37         }
    38         printf("%I64d\n",dp[n]);
    39     }
    40     return 0;
    41 }

    2.POJ 3709 K-Anonymous Sequence

    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define read freopen("in.txt","r",stdin)
     5 #define write freopen("out.txt","w",stdout)
     6 using namespace std;
     7 #define maxn 500005
     8 typedef long long ll;
     9 int num[maxn];
    10 ll sum[maxn],dp[maxn];
    11 struct str
    12 {
    13     int pos;
    14     ll x,y;
    15 } que[maxn];
    16 bool checkTail(int p1,int p2,ll tx,ll ty)
    17 {
    18     return (ty-que[p2].y)*(que[p2].x-que[p1].x)
    19             <=(que[p2].y-que[p1].y)*(tx-que[p2].x);
    20 }
    21 bool checkHead(int p1,int p2,int pos)
    22 {
    23     return que[p2].y-que[p1].y<pos*(que[p2].x-que[p1].x);
    24 }
    25 int main()
    26 {
    27     //read;write;
    28     int cas,n,m;
    29     num[0]=sum[0]=0;
    30     scanf("%d",&cas);
    31     while(cas--)
    32     {
    33         scanf("%d%d",&n,&m);
    34         for(int i=1;i<=n;i++)
    35         {
    36             scanf("%d",&num[i]);
    37             sum[i]=num[i]+sum[i-1];
    38         }
    39         for(int i=m;i<2*m;i++)dp[i]=sum[i]-i*num[1];
    40         int head=1,tail=0;
    41         que[++tail].x=num[1],que[tail].y=0,que[tail].pos=0;
    42         for(int i=2*m;i<=n;i++)
    43         {
    44             int t=i-m;
    45             ll tx=num[t+1],ty=dp[t]-sum[t]+t*num[t+1];
    46             while(tail>head&&checkTail(tail-1,tail,tx,ty))tail--;
    47             que[++tail].x=tx,que[tail].y=ty,que[tail].pos=t;
    48             while(tail>head&&checkHead(head,head+1,i))head++;
    49             int pos=que[head].pos;
    50             dp[i]=dp[pos]+sum[i]-sum[pos]-(ll)(i-pos)*num[pos+1];
    51         }
    52         printf("%I64d\n",dp[n]);
    53     }
    54     return 0;
    55 }

    3.UVALive 4726 Average

    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 #define maxn 150000
     6 char ss[maxn];
     7 long long sum[maxn];
     8 int que[maxn];
     9 bool checkTail(int p1,int p2,int p3)
    10 {
    11     return (sum[p3]-sum[p2])*(p2-p1)<=(sum[p2]-sum[p1])*(p3-p2);
    12 }
    13 bool checkHead(int p1,int p2,int p3)
    14 {
    15     return (sum[p3]-sum[p2])*(p3-p1)>=(sum[p3]-sum[p1])*(p3-p2);
    16 }
    17 int checkAns(int s1,int e1,int s2,int e2)
    18 {
    19     long long t1=(sum[e2]-sum[s2])*(e1-s1);
    20     long long t2=(sum[e1]-sum[s1])*(e2-s2);
    21     if(t1==t2)return 1;
    22     else if(t1>t2)return 2;
    23     return 0;
    24 }
    25 int main()
    26 {
    27     sum[0]=0;
    28     int cas,n,m;
    29     scanf("%d",&cas);
    30     while(cas--)
    31     {
    32         scanf("%d%d",&n,&m);
    33         scanf("%s",ss);
    34         for(int i=1;i<=n;i++)sum[i]=sum[i-1]+ss[i-1]-'0';
    35         int head=1,tail=0,left=1,right=m;
    36         for(int i=m;i<=n;i++)
    37         {
    38             int t=i-m;
    39             while(tail>head&&checkTail(que[tail-1],que[tail],t))tail--;
    40             que[++tail]=t;
    41             while(tail>head&&checkHead(que[head],que[head+1],i))head++;
    42             t=checkAns(left-1,right,que[head],i);
    43             if(t==1&&right-left>i-que[head]-1)left=que[head]+1,right=i;
    44             else if(t==2)left=que[head]+1,right=i;
    45         }
    46         cout<<left<<" "<<right<<endl;
    47     }
    48     return 0;
    49 }

    4[HNOI2008]玩具装箱toy

    View Code
     1 /**************************************************************
     2     Problem: 1010
     3     User: sdau20104686
     4     Language: C++
     5     Result: Accepted
     6     Time:344 ms
     7     Memory:2248 kb
     8 ****************************************************************/
     9  
    10 #include <iostream>
    11 #include <cstring>
    12 #include <cstdio>
    13 #include <cstdlib>
    14 #include <cmath>
    15 #include <string>
    16 #include <vector>
    17 #include <list>
    18 #include <map>
    19 #include <queue>
    20 #include <stack>
    21 #include <bitset>
    22 #include <algorithm>
    23 #include <numeric>
    24 #include <functional>
    25 using namespace std;
    26 typedef long long ll;
    27 #define read freopen("in.txt","r",stdin)
    28 #define write freopen("out.txt","w",stdout)
    29 #define maxn 50005
    30 ll sum[maxn];
    31 ll dp[maxn];
    32 int que[maxn];
    33 ll n,m;
    34 bool checkHead(int i,int j,int k)
    35 {
    36     ll tk=sum[k]+k,tj=sum[j]+j,ti=sum[i]+i;
    37     ll rk=dp[k]+tk*tk+2*m*tk;
    38     ll rj=dp[j]+tj*tj+2*m*tj;
    39     if((rk-rj)<2*ti*(tk-tj))return true;
    40     return false;
    41 }
    42 bool checkTail(int i,int j,int k)
    43 {
    44     ll tk=sum[k]+k,tj=sum[j]+j,ti=sum[i]+i;
    45     ll rk=dp[k]+tk*tk+2*m*tk;
    46     ll rj=dp[j]+tj*tj+2*m*tj;
    47     ll ri=dp[i]+ti*ti+2*m*ti;
    48     if((ri-rk)*(tk-tj)<=(rk-rj)*(ti-tk))return true;
    49     return false;
    50 }
    51 int main()
    52 {
    53     //read;
    54     while(~scanf("%I64d%I64d",&n,&m))
    55     {
    56         m++;
    57         sum[0]=0,dp[0]=0,que[0]=0;
    58         for(int i=1;i<=n;i++)
    59         {
    60             scanf("%I64d",&sum[i]);
    61             sum[i]+=sum[i-1];
    62         }
    63         int head=0,tail=0;
    64         for(int i=1;i<=n;i++)
    65         {
    66             while(tail>head&&checkHead(i,que[head],que[head+1]))head++;
    67             ll t=(i-que[head]+sum[i]-sum[que[head]]-m);
    68             dp[i]=dp[que[head]]+t*t;
    69             while(tail>head&&checkTail(i,que[tail-1],que[tail]))tail--;
    70             que[++tail]=i;
    71         }
    72         printf("%lld\n",dp[n]);
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    txt文本处理---行未添加逗号
    wav转txt格式的代码实现(c,python)
    程序员的健康--预防
    程序员的健康--病因
    朴素贝叶斯算法简介及python代码实现分析
    hdf 5文件格式及python中利用h5py模块读写h5文件
    C 语言restrict 关键字的概念及使用例子
    一个程序员卑微的目标
    【ES】学习4-结构化搜索
    【python】正则表达式中的转义问题
  • 原文地址:https://www.cnblogs.com/mcflurry/p/2753035.html
Copyright © 2011-2022 走看看