【专题】单调队列/斜率优化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\n",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\n",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\n",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问题






你可能感兴趣的:(【专题】单调队列/斜率优化DP)