• 【专题】单调队列/斜率优化DP



    一、单调队列

    志愿者选拔 O(n)

    struct STU{
        char name[7];
        int rp;
    };
    
    int que[2111111];
    int idx[2111111];
    
    int main()
    {
        int T,head,tail;
        char gs[111];
        scanf("%d",&T);
        while (T--)
        {
            int cas,cnt;
            head=tail=0;
            cas=cnt=0;
            while (scanf("%s",gs))
            {
                if (strcmp(gs,"END")==0) break;
                if (strcmp(gs,"C")==0)
                {
                    cnt++;
                    STU tmp;
                    scanf("%s%d",tmp.name,&tmp.rp);
                    while (head<tail&&que[tail-1]<=tmp.rp) tail--;
                    idx[tail]=cnt;
                    que[tail++]=tmp.rp;
                }
                if (strcmp(gs,"G")==0)
                {
                    cas++;
                    if (idx[head]<=cas) head++;
                }
                if (strcmp(gs,"Q")==0)
                {
                    if (head<tail) cout<<que[head]<<endl;
                    else cout<<-1<<endl;
                }
            }
        }
        return 0;
    }
    

    Sliding Window O(n)

    #include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    
    const int maxn=1111111;
    
    int a[maxn];
    int que[maxn];
    int idx[maxn];
    
    int main()
    {
        int n,k;
        int head,tail,cas;
        while (~scanf("%d%d",&n,&k))
        {
            for (int i=0;i<n;i++) scanf("%d",&a[i]);
            head=tail=cas=0;
            for (int i=0;i<n;i++)
            {
                while (head<tail&&que[tail-1]>=a[i]) tail--;
                idx[tail]=i;
                que[tail++]=a[i];
                while (head<tail&&i-idx[head]>=k) head++;
                if (i>=k-1) cout<<que[head]<<" ";
                else if (i>=k-1&&i==n-1) cout<<que[head];
            }
            cout<<endl;
            head=tail=cas=0;
            for (int i=0;i<n;i++)
            {
                while (head<tail&&que[tail-1]<=a[i]) tail--;
                idx[tail]=i;
                que[tail++]=a[i];
                while (head<tail&&i-idx[head]>=k) head++;
                if (i>=k-1&&i<n-1) cout<<que[head]<<" ";
                else if (i>=k-1&&i==n-1) cout<<que[head];
            }
            cout<<endl;
        }
        return 0;
    }
    

    Max Sum of Max-K-sub-sequence O(n)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    int a[411111];
    int f[411111];
    int que[1111111];
    int pt[1111111];
    int n,k;
    int T;
    int head,tail;
    int sum[411111];
    int max_sum,start,end;
    
    int main()
    {
        scanf("%d",&T);
        while (T--)
        {
            memset(f,0,sizeof(f));
            memset(que,0,sizeof(que));
            memset(pt,0,sizeof(pt));
            memset(sum,0,sizeof(sum));
            scanf("%d%d",&n,&k);
            for (int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                a[i+n]=a[i];
            }
            for (int i=1;i<=n+k;i++)
            {
                sum[i]+=sum[i-1]+a[i];
            }
            //f[i]=max(sum[i]-sum[k]);
            head=tail=0;
            max_sum=start=end=-1e9;
            for (int i=1;i<=n+k;i++)
            {
                while ((head<tail)&&(i-pt[head]>k)) head++;
                while ((head<tail)&&(sum[i-1]<=que[tail-1])) tail--;
                que[tail]=sum[i-1],pt[tail++]=i-1;
                f[i]=sum[i]-que[head];
                if (f[i]>max_sum)
                {
                    max_sum=f[i];
                    start=pt[head]+1;
                    end=i;
                }
            }
            if (start>n) start=start-n;
            if (end>n) end=end-n;
            printf("%d %d %d
    ",max_sum,start,end);
        }
        return 0;
    }


    二、单调队列dp


    Trade O(n)

    /** head-file **/
    
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <iomanip>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <list>
    #include <set>
    #include <map>
    #include <algorithm>
    
    /** define-for **/
    
    #define REP(i, n) for (int i=0;i<int(n);++i)
    #define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
    #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
    #define REP_1(i, n) for (int i=1;i<=int(n);++i)
    #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
    #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
    #define REP_N(i, n) for (i=0;i<int(n);++i)
    #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
    #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
    #define REP_1_N(i, n) for (i=1;i<=int(n);++i)
    #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
    #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
    
    /** define-useful **/
    
    #define clr(x,a) memset(x,a,sizeof(x))
    #define sz(x) int(x.size())
    #define see(x) cerr<<#x<<" "<<x<<endl
    #define se(x) cerr<<" "<<x
    #define pb push_back
    #define mp make_pair
    
    /** test **/
    
    #define Display(A, n, m) {                      
        REP(i, n){                                  
            REP(j, m) cout << A[i][j] << " ";       
            cout << endl;                           
        }                                           
    }
    
    #define Display_1(A, n, m) {                    
        REP_1(i, n){                                
            REP_1(j, m) cout << A[i][j] << " ";     
            cout << endl;                           
        }                                           
    }
    
    using namespace std;
    
    /** typedef **/
    
    typedef long long LL;
    
    /** Add - On **/
    
    const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
    const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
    const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
    
    const int MOD = 1000000007;
    const int INF = 0x3f3f3f3f;
    const long long INFF = 1LL << 60;
    const double EPS = 1e-9;
    const double OO = 1e15;
    const double PI = acos(-1.0); //M_PI;
    
    const int maxn=2222;
    int f[maxn][maxn];
    int AP[maxn],BP[maxn],AS[maxn],BS[maxn];
    int MaxP,W,T;
    /**
        f[i][j]=max(f[i-1][j],f[i-W-1][k]-AP[i]*(j-k),f[i-W-1][k]+BP[i]*(k-j))
        f[i-W-1][k]-AP[i]*(j-k)
        =f[i-W-1][k]+AP[i]*k-AP[i]*j
        f[i-W-1][k]+BP[i]*(k-j)
        =f[i-W-1][k]+BP[i]*k-BP[i]*j
    **/
    int que[maxn];
    int idx[maxn];
    
    int main()
    {
        int CAS;
        int head,tail,ans;
        scanf("%d",&CAS);
        while (CAS--)
        {
            scanf("%d%d%d",&T,&MaxP,&W);
            REP_1(i,T)
            {
                scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]);
            }
            REP_1(i,MaxP) f[0][i]=-INF;
            f[0][0]=0;
            ans=0;
            FOR_1(i,1,T)
            {
                FOR_1(j,0,MaxP) f[i][j]=f[i-1][j];
                if (i-W-1<1)
                {
                    FOR_1(j,0,AS[i]) f[i][j]=max(f[i][j],-AP[i]*j);
                    continue;
                }
                head=tail=0;
                FOR_1(j,0,MaxP)
                {
                    while (head<tail&&que[tail-1]<=f[i-W-1][j]+AP[i]*j) tail--;
                    que[tail]=f[i-W-1][j]+AP[i]*j;
                    idx[tail++]=j;
                    while (head<tail&&j-idx[head]>AS[i]) head++;
                    f[i][j]=max(f[i][j],que[head]-AP[i]*j);
                    ans=max(ans,f[i][j]);
                }
                head=tail=0;
                DWN_1(j,MaxP,0)
                {
                    while (head<tail&&que[tail-1]<=f[i-W-1][j]+BP[i]*j) tail--;
                    que[tail]=f[i-W-1][j]+BP[i]*j;
                    idx[tail++]=j;
                    while (head<tail&&idx[head]-j>BS[i]) head++;
                    f[i][j]=max(f[i][j],que[head]-BP[i]*j);
                    ans=max(ans,f[i][j]);
                }
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    

    SubsequenceO(n)

    /** head-file **/
    
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <iomanip>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <list>
    #include <set>
    #include <map>
    #include <algorithm>
    
    /** define-for **/
    
    #define REP(i, n) for (int i=0;i<int(n);++i)
    #define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
    #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
    #define REP_1(i, n) for (int i=1;i<=int(n);++i)
    #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
    #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
    #define REP_N(i, n) for (i=0;i<int(n);++i)
    #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
    #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
    #define REP_1_N(i, n) for (i=1;i<=int(n);++i)
    #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
    #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
    
    /** define-useful **/
    
    #define clr(x,a) memset(x,a,sizeof(x))
    #define sz(x) int(x.size())
    #define see(x) cerr<<#x<<" "<<x<<endl
    #define se(x) cerr<<" "<<x
    #define pb push_back
    #define mp make_pair
    
    /** test **/
    
    #define Display(A, n, m) {                      
        REP(i, n){                                  
            REP(j, m) cout << A[i][j] << " ";       
            cout << endl;                           
        }                                           
    }
    
    #define Display_1(A, n, m) {                    
        REP_1(i, n){                                
            REP_1(j, m) cout << A[i][j] << " ";     
            cout << endl;                           
        }                                           
    }
    
    using namespace std;
    
    /** typedef **/
    
    typedef long long LL;
    
    /** Add - On **/
    
    const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
    const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
    const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
    
    const int MOD = 1000000007;
    const int INF = 0x3f3f3f3f;
    const long long INFF = 1LL << 60;
    const double EPS = 1e-9;
    const double OO = 1e15;
    const double PI = acos(-1.0); //M_PI;
    const int maxn=110000;
    int a[maxn];
    typedef pair<int,int> PII;
    deque<PII>q1,q2;
    int main()
    {
        int n,m,k;
        int ans,now;
        while (~scanf("%d%d%d",&n,&m,&k))
        {
            ans=0;
            now=0;
            q1.clear();
            q2.clear();
            REP(i,n)
            {
                scanf("%d",&a[i]);
                while (!q1.empty()&&q1.back().first<=a[i]) q1.pop_back();
                q1.push_back(mp(a[i],i));
                while (!q2.empty()&&q2.back().first>=a[i]) q2.pop_back();
                q2.push_back(mp(a[i],i));
                while (!q1.empty()&&!q2.empty()&&q1.front().first-q2.front().first>k)
                {
                    if (q1.front().second<q2.front().second)
                    {
                        now=q1.front().second+1;
                        q1.pop_front();
                    }
                    else
                    {
                        now=q2.front().second+1;
                        q2.pop_front();
                    }
                }
                if (!q1.empty()&&!q2.empty()&&q1.front().first-q2.front().first>=m)
                    ans=max(ans,i-now+1);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    其他题目

    MUTC8 E- One hundred layer 单调队列dp

    MUTC7 C - Dragon Ball 单调队列dp


    三、斜率优化

    MAX Average Problem O(n)

    /** head-file **/
    
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <iomanip>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <list>
    #include <set>
    #include <map>
    #include <algorithm>
    
    /** define-for **/
    
    #define REP(i, n) for (int i=0;i<int(n);++i)
    #define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
    #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
    #define REP_1(i, n) for (int i=1;i<=int(n);++i)
    #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
    #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
    #define REP_N(i, n) for (i=0;i<int(n);++i)
    #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
    #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
    #define REP_1_N(i, n) for (i=1;i<=int(n);++i)
    #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
    #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
    
    /** define-useful **/
    
    #define clr(x,a) memset(x,a,sizeof(x))
    #define sz(x) int(x.size())
    #define see(x) cerr<<#x<<" "<<x<<endl
    #define se(x) cerr<<" "<<x
    #define pb push_back
    #define mp make_pair
    
    /** test **/
    
    #define Display(A, n, m) {                      
        REP(i, n){                                  
            REP(j, m) cout << A[i][j] << " ";       
            cout << endl;                           
        }                                           
    }
    
    #define Display_1(A, n, m) {                    
        REP_1(i, n){                                
            REP_1(j, m) cout << A[i][j] << " ";     
            cout << endl;                           
        }                                           
    }
    
    using namespace std;
    
    /** typedef **/
    
    typedef long long LL;
    
    /** Add - On **/
    
    const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
    const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
    const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
    
    const int MOD = 1000000007;
    const int INF = 0x3f3f3f3f;
    const long long INFF = 1LL << 60;
    const double EPS = 1e-9;
    const double OO = 1e15;
    const double PI = acos(-1.0); //M_PI;
    const int maxn=111111;
    
    int a[maxn];
    int sum[maxn];
    int que[maxn];
    int head,tail;
    
    int getin()
    {
        char ch=' ';
        while (ch<'0'||ch>'9') ch=getchar();
        int x=0;
        while (ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x;
    }
    
    double getup(int i,int j)
    {
        return sum[i]-sum[j];
    }
    int getdown(int i,int j)
    {
        return i-j;
    }
    long long cross(int a,int b,int c)
    {
        long long x1=b-a;
        long long y1=sum[b]-sum[a];
        long long x2=c-b;
        long long y2=sum[c]-sum[b];
        return x1*y2-y1*x2;
    }
    int dbsearch(int l,int r,int i)
    {
        while (l<r)
        {
            int mid=(l+r)/2;
            if (cross(que[mid],que[mid+1],i)<0) r=mid;
            else l=mid+1;
        }
        return l;
    }
    
    int main()
    {
        int n,k;
        while (~scanf("%d%d",&n,&k))
        {
            sum[0]=0;
            REP_1(i,n)
            {
                a[i]=getin();
                sum[i]=sum[i-1]+a[i];
            }
            head=tail=0;
            que[tail++]=0;
            double ans=0;
            FOR_1(i,k,n)
            {
                int j=i-k;
                while (head+1<tail&&cross(que[tail-2],que[tail-1],j)<0) tail--;
                que[tail++]=j;
                int tmp=dbsearch(0,tail-1,i);
                double f=double(sum[i]-sum[que[tmp]])/(i-que[tmp]);
                ans=max(ans,f);
            }
            printf("%0.2f
    ",ans);
        }
        return 0;
    }
    


    Print ArticleO(n)

    /** head-file **/
    
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <iomanip>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <list>
    #include <set>
    #include <map>
    #include <algorithm>
    
    /** define-for **/
    
    #define REP(i, n) for (int i=0;i<int(n);++i)
    #define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
    #define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
    #define REP_1(i, n) for (int i=1;i<=int(n);++i)
    #define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
    #define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
    #define REP_N(i, n) for (i=0;i<int(n);++i)
    #define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
    #define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
    #define REP_1_N(i, n) for (i=1;i<=int(n);++i)
    #define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
    #define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
    
    /** define-useful **/
    
    #define clr(x,a) memset(x,a,sizeof(x))
    #define sz(x) int(x.size())
    #define see(x) cerr<<#x<<" "<<x<<endl
    #define se(x) cerr<<" "<<x
    #define pb push_back
    #define mp make_pair
    
    /** test **/
    
    #define Display(A, n, m) {                      
        REP(i, n){                                  
            REP(j, m) cout << A[i][j] << " ";       
            cout << endl;                           
        }                                           
    }
    
    #define Display_1(A, n, m) {                    
        REP_1(i, n){                                
            REP_1(j, m) cout << A[i][j] << " ";     
            cout << endl;                           
        }                                           
    }
    
    using namespace std;
    
    /** typedef **/
    
    typedef long long LL;
    
    /** Add - On **/
    
    const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
    const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
    const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
    
    const int MOD = 1000000007;
    const int INF = 0x3f3f3f3f;
    const long long INFF = 1LL << 60;
    const double EPS = 1e-9;
    const double OO = 1e15;
    const double PI = acos(-1.0); //M_PI;
    /**
        f[i]=min( f[j]+(sum[i]-sum[j])^2+M )
        y为f[j]+sum[j]^2,x为2*sum[j],斜率为sum[i],截距为f[i]
    **/
    const int maxn=550000;
    int n,m;
    int a[maxn];
    int f[maxn];
    int que[maxn];
    int head,tail;
    int sum[maxn];
    int gety(int j){return f[j]+sum[j]*sum[j];}
    int getx(int j){return 2*sum[j];}
    int dp_sol(int i,int j){return f[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+m;}
    bool cmp_idx(int i,int j,int k)
    {
        return (gety(i)-gety(j))*(getx(j)-getx(k))<=(gety(j)-gety(k))*(getx(i)-getx(j));
    }
    int main()
    {
        while (~scanf("%d%d",&n,&m))
        {
            memset(f,0,sizeof(f));
            sum[0]=0;
            REP_1(i,n)
            {
                scanf("%d",&a[i]);
                sum[i]=sum[i-1]+a[i];
            }
            head=tail=0;
            que[tail++]=0;
            f[0]=0;
            for (int i=1;i<=n;i++)
            {
                while (tail-head>1&&dp_sol(i,que[head])>=dp_sol(i,que[head+1])) head++;
                f[i]=dp_sol(i,que[head]);
                while (tail-head>1&&cmp_idx(i,que[tail-1],que[tail-2])) tail--;
                que[tail++]=i;
            }
            cout<<f[n]<<endl;
        }
        return 0;
    }
    


    其他题目

    Codeforces Round #189 (Div. 2) 解题报告



    四、BST解决不单调的dp问题






  • 相关阅读:
    用WinForm写的员工考勤项目!!!!!!
    洛谷P1892《[BOI2003]团伙》
    洛谷P1821《[USACO07FEB]银牛派对Silver Cow Party》
    洛谷P1149《火柴棒等式》
    2017 国庆清北刷题冲刺班《角谷猜想》
    洛谷P2330《[SCOI2005]繁忙的都市》
    洛谷P1955《[NOI2015]程序自动分析》
    洛谷P1536《村村通》
    Windows 10 体验记
    洛谷P1102《A-B数对》
  • 原文地址:https://www.cnblogs.com/cyendra/p/3681608.html
Copyright © 2020-2023  润新知