贪玩(van)蓝月

本文介绍了针对一道最窄题目描述的解题过程,重点探讨了利用CDQ分治策略解决该问题的思路。通过分析性质,揭示了如何从已知的k个答案序列扩展到k+2个答案序列。文章详细阐述了三种可能的情况,并强调了维护最大值和最小值的重要性。最后,总结了CDQ分治在优化动态规划算法上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目 

最窄的题目描述。。。

思路&题解

自己的思路

这是不可能有的

正解

首先需要发现一个性质,如果现在已经求出k的答案,那么k+2的答案序列就一定是在k的答案序列中插入两个(可以是末尾与开头) 数所得到,至于为什么,其实我也不知道,那么考虑k+2的转换,考虑CDQ

假设对于k,在区间l-mid选了k1个点,mid+1-r选了k2个点

那么对于k+2,就有一下情况:

1.在区间l-mid选k1+1个点,mid+1-r选k2+1个点

2.在区间l-mid选k1个点,mid+1-r选k2+2个点

3.在区间l-mid选k1+2个点,mid+1-r选k2个点

但是由于它是加减加减的,所以还要维护最大值和最小值

总结

CDQ分治是解决用一个子问题来计算对另一个子问题的贡献的算法,所以这道题可以刚好使用,因此dp也可以用此来优化

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 3;
int n , a[MAXN] , f[MAXN][23][2];
int w[MAXN][2];
void cdq( int l , int r , int step ){
    if( l == r ) {
        f[l][step][0] = a[l] , f[l][step][1] = a[l];
        return ;
    }
    int mid = ( l + r )>> 1;
    cdq( l , mid , step + 1 );
    cdq( mid + 1 , r , step + 1 );
    for( int i = l ; i <= r ; i ++ )
        f[i][step][1] = 0x3f3f3f3f , f[i][step][0] = -0x3f3f3f3f;
    int k1 = 0 , k2 = 0;
    if( f[l][step+1][0] > f[mid+1][step+1][0] ) f[l][step][0] = f[l][step+1][0] , k1 = 1;
    else f[l][step][0] = f[mid+1][step+1][0] , k2 = 1;
    for( int i = l + 2 ; i <= r ; i += 2 ){
        int k11 , k22 , tmp ;
        if( l + k1 <= mid && mid + k2 + 1 <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值