ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AtCoder Grand Contest 040 E

2019-11-04 11:57:13  阅读:347  来源: 互联网

标签:AtCoder 填入 Contest int 情况 operator 转移 dp 040


传送门:https://atcoder.jp/contests/agc040/tasks/agc040_e

sol:

考虑只做$operator 1$ 或者 $operator 2$
只做$operator 1$的情况下:
做的次数$+1$的情况 当且仅当存在$Ai>A_{i+1}$
只做$operator 2$的情况下
做的次数+1的情况 当且仅当$Ai<A_{i+1}$
发现$operator 1$的操作并不会影响到 $operator 2$ 的操作
所以我们可以考虑先做$operator 1$ 再统一做$operator 2$
于是我们就发现原问题抽象一下
就是 求两个序列$x$和$y$
其中所有$x_i+y_i=A_i$
贡献是$\sum[xi>xi+1]$+$\sum[yi<yi+1]$
最小化这个贡献
可以$dp$
$dp_{i,j}$表示考虑了前$i$个数,当前这个$x_i$填入$j$的情况
常规转移就是枚举上一位数字
然后考虑加速这个转移
观察转移过程
发现对于$j$递增的情况,$dp$的值一定是单调不增的
我们又可以发现 $dp_{i,0}<=dp_{i,A_i}+2$

这个位置填入$0$的话,最多和填入$A_i$差异$2$ 我们可以修改$A_i$使得这个一定被达到
于是我们就发现
也就是说我们只需要知道的东西是 $dp_{i,0}$ 还有 其中有多少个$pos$是增的[这种$pos$绝对不会超过两个

直接转移即可,转移$O(1)$,总效率$O(n)$

Code:

#include <bits/stdc++.h>
using namespace std;
int N,a[200005];
int main(){
    scanf("%d",&N);
    for (int i=1;i<=N;i++)
        scanf("%d",&a[i]);
    int ans=0,now=0,v[2]{};
    for (int i=1;i<=N+1;i++){
        int p[2]{0,a[i]-now};
        if (p[0]<p[1]) swap(p[0],p[1]);
        int nex[3]{1000000000,1000000000,0};
        for (int j=0;j<2;j++)
            for (int k=0;k<2;k++)
                nex[j+k]=min(max(0,v[j]+p[k]),nex[j+k]);
        int d=nex[0]>a[i];
        for (int j=0;j<2;j++)
            v[j]=nex[j+d];
        ans+=d;
        now=a[i];
    }
    cout<<ans;
    return 0;
}

 

标签:AtCoder,填入,Contest,int,情况,operator,转移,dp,040
来源: https://www.cnblogs.com/si--nian/p/11791273.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有