• 单调队列优化DP 上 day46


    我超 好jian的t宝

    今天也没有看到jls登顶www

    一些小理解:dp就是用集合来概括 这样就可以用递推的方式来最优解优化

    而dp的状态自然千奇百怪 可谓条条大路

    AcWing 135. 最大子序和

    想的区间dp 单调队列就是i~j之间的max 

    但是无奈区间dp 我不会空间优化

    那寄了 没想到可以用前缀和 我们维护一个m的滑动窗口即可

    然后要注意的就是 我们最开始要加入下标0 因为这个也是一个合法的下标(我们维护的

    是前面长度为m的区间 

    然后就是标号要大于m才 pop_front 始终记得我们维护的是前面长度为m的滑动窗口

    这样前缀和就直接是不用减一的

    这里解释一下为什么不用常用的前缀和-1的写法

    因为我们维护的单调队列和求的东西要有直接关系 要是我们这边球的是-1 那么维护的也应该是-1

    那么为什么不久直接维护0 0 呢

    1. #include
    2. using namespace std;
    3. const int N = 3e5+10;
    4. const int M = 1<<12;
    5. //const int mod = 1e9+7;
    6. #define int long long
    7. #define LL long long
    8. #define endl '\n'
    9. #define Endl '\n'
    10. #define _ 0
    11. #define inf 0x3f3f3f3f3f3f3f3f
    12. #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
    13. int n,m,s[N];
    14. signed main(){
    15. fast
    16. cin>>n>>m;
    17. int ans=-2e9;
    18. for(int i=1;i<=n;i++){
    19. cin>>s[i];
    20. ans=max(ans,s[i]);
    21. s[i]+=s[i-1];
    22. }
    23. deque<int>dq;//维护一个上升队列
    24. dq.push_back(0);
    25. for(int i=1;i<=n;i++){
    26. while(!dq.empty()&&s[dq.back()]>=s[i])dq.pop_back();
    27. dq.push_back(i);
    28. while(!dq.empty()&&i-dq.front()>m)dq.pop_front();
    29. if(!dq.empty()&&dq.front()-i)ans=max(ans,s[i]-s[dq.front()]);
    30. }
    31. cout<
    32. return ~~(0^_^0);
    33. }

    1087. 修剪草坪

    成功把自己绕进去了 哈哈

    其实最开始就写对了 但是back 写成 front 以为自己思路出了问题

    其实不是啊

    我们最开始会想到二维的一个状态表示 f[i][j]表示第i个并且已经连了j个

    可是这个确实是找不到啥单调性

    那我们可以思考变成一维的情况 f[i]表示第i个并且合法的方案

    那状态计算自然就出来了

    f[i]=max(f[i-1],f[i-j-1]+s[i]-s[i-j])       (0<=j<=m)

    我们把s[i]提出来 max{f[i-j-1]-s[i-j]} 这个的意思就是前面长度为m的滑动窗口中的max值

    故可以用单调队列优化 为啥不把s[i]放进去 其实s[i]是一个实时的东西枚举到每一位s[i]就是那个

    让后还要考虑的就是i可能和j 相等 是什么情况?

    就相当与是一个长度为j+1的线段的和 就是0+s[i]-s[0] 即可 所以我们要设所有f[-1]变成0

    1. #include
    2. using namespace std;
    3. const int N = 1e5+10;
    4. const int M = 1<<12;
    5. //const int mod = 1e9+7;
    6. #define int long long
    7. #define LL long long
    8. #define endl '\n'
    9. #define Endl '\n'
    10. #define _ 0
    11. #define inf 0x3f3f3f3f3f3f3f3f
    12. #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
    13. int f[N],s[N];
    14. LL g(int i){
    15. return f[i-1]-s[i];
    16. }
    17. signed main(){
    18. fast
    19. int n,m;cin>>n>>m;
    20. for(int i=1;i<=n;i++){
    21. cin>>s[i];
    22. s[i]+=s[i-1];
    23. }
    24. deque<int>dq;//下降
    25. dq.push_back(0);
    26. for(int i=1;i<=n;i++){
    27. while(!dq.empty()&&(f[i-1]-s[i])>=(f[dq.back()-1]-s[dq.back()]))dq.pop_back();
    28. dq.push_back(i);
    29. while(!dq.empty()&&i-dq.front()>m)dq.pop_front();
    30. f[i]=max(f[i-1],f[dq.front()-1]-s[dq.front()]+s[i]);
    31. }
    32. cout<
    33. return ~~(0^_^0);
    34. }

    1088. 旅行问题

    拆成链都知道把

    前缀和也要处理是吧

    但是这么想 能让我们是线性的做法呢 其实也不是很难想啊

    我们只要让每个区间的前缀和都大于0 就可以了

    s[j]-s[i]>=0 (i<=j<=i+n)

    然后就是模板了

    但是这道题让我们正着反着只要一边可以就算可以

    但是反向时应该是 o[i]-d[i-1] 这是一个坑点

    1. #include
    2. using namespace std;
    3. const int N = 2e6+10;
    4. const int M = 1<<12;
    5. //const int mod = 1e9+7;
    6. #define int long long
    7. #define LL long long
    8. #define endl '\n'
    9. #define Endl '\n'
    10. #define _ 0
    11. #define inf 0x3f3f3f3f3f3f3f3f
    12. #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
    13. int s[N],o[N],d[N];
    14. bool ans[N];
    15. signed main(){
    16. fast
    17. int n;cin>>n;
    18. for(int i=1;i<=n;i++){
    19. cin>>o[i];
    20. o[i+n]=o[i];
    21. cin>>d[i];
    22. d[i+n]=d[i];
    23. }
    24. for(int i=1;i<=n<<1;i++){
    25. s[i]+=(o[i]-d[i])+s[i-1];
    26. }
    27. deque<int>dq;//min
    28. for(int i=n<<1;i>=1;i--){
    29. while(!dq.empty()&&s[i]<=s[dq.back()])dq.pop_back();
    30. dq.push_back(i);
    31. while(!dq.empty()&&dq.front()-i>n)dq.pop_front();
    32. if(!dq.empty()&&s[dq.front()]-s[i-1]>=0)ans[i]=true;
    33. }
    34. dq.clear();
    35. d[0]=d[n];
    36. for(int i=1;i<=n<<1;i++){
    37. s[i]=0;
    38. s[i]+=(o[2*n-i+1]-d[2*n-i])+s[i-1];
    39. }
    40. for(int i=n<<1;i>=1;i--){
    41. while(!dq.empty()&&s[i]<=s[dq.back()])dq.pop_back();
    42. dq.push_back(i);
    43. while(!dq.empty()&&dq.front()-i>n)dq.pop_front();
    44. if(!dq.empty()&&s[dq.front()]-s[i-1]>=0)ans[n-i+1]=true;
    45. }
    46. for(int i=1;i<=n;i++){
    47. if(ans[i])cout<<"TAK"<
    48. else cout<<"NIE"<
    49. }
    50. return ~~(0^_^0);
    51. }

  • 相关阅读:
    T507修改分区方法-Linux、Android系统适用
    UE5实现相机水平矫正
    【外汇天眼】携手共护外汇投资:2023年WikiFX晚宴首次在越南圆满举行
    科技资讯|Vision Pro头显无损音频仅限USB-C AirPods Pro 2耳机
    微信公众号根据关键词取文章列表 API
    Vue3初始化加载loading
    羧基荧光素-氨基.盐酸盐,FAM-NH2.HCl,138589-19-2
    94. 二叉树的中序遍历(Swift实现, 迭代)
    Java(一)--- DOS,文档注释,代码规范
    Flutter中 ElevatedButton取代RaisedButton
  • 原文地址:https://blog.csdn.net/qq_23852555/article/details/126090269