单调队列及单调队列优化DP详解

单调队列

详解博客

  • 三个步骤:
    1. 判断队头决策与i的距离是否超出M的范围,若超出则出队
    2. 此时队头就是右端点为i时,左端点j的最优选择
    3. 不断删除队尾决策,直到队尾的S值小于S[i]。然后把i作为一个新的决策入队。
//单调队列板子 (区间和最大)
int l = 1, r = 1;
q[1] = 0;
for(int i = 1; i <= n; ++i){
	while(l <= r && q[l] < i - m) l++; //step 1
	ans = max(ans,sum[i] - sum[q[l]]); // step 2
	while(l <= r && sum[q[r]] >= sum[i]) r--; //step 3
    q[++r] = i;
}
//区间最大值
int l = 1, r = 0;
for(int i = 1; i< =n; ++i) {
	while (l <= r && s[i] >= s[q[r]]) r--;
	q[++r] = i;
	while (l <= r && q[l] < i - m) ++l;
}
  • 区间最小值同理

  • 例题 CF372C

  • #include
    using namespace std;
    #pragma GCC optimize(2)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    ll n,m,d;
    const int INF=1e18;
    const int N = 310;
    struct node{
        ll a,b,t;
    }st[N];
    ll dp[2][150010];
    int que[150100];
    
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        scanf("%I64d%I64d%I64d", &n, &m, &d);
        for(int i = 1; i <= m; ++i) scanf("%I64d%I64d%I64d",&st[i].a, &st[i].b, &st[i].t);
        ll nowTime = st[1].t;
        int now = 0;
        for(int i = 1; i <= m; i++) {
            int l = 1,r = 0,k = 1;
            now ^= 1;
            if(nowTime == st[i].t) {
                for(int j = 1; j <= n; ++j) {
                    dp[now][j] = dp[now ^ 1][j] + st[i].b - abs(st[i].a - j);
                }
            } else {
                ll t=st[i].t - nowTime;
                nowTime = st[i].t;
                for(int j = 1; j <= n; ++j ) {
                    while (k <=n && k <= j + d * t) {
                        while ( l <= r && dp[now ^ 1][k] >= dp[now ^ 1][que[r]]) r--;
                        que[++r] = k;
                        ++k;
                    }
                    while (l <= r && que[l] < j - t * d) ++l;
                    dp[now][j] = dp[now ^ 1][que[l]] + st[i].b - abs(st[i].a - j);
                }
            }
        }
        ll ans = -INF;
        for(int i = 1; i <= n; ++i)
            ans = max(ans, dp[now][i]);
        printf("%I64d\n",ans);
        return 0;
    }
    

你可能感兴趣的:(算法)