P3558 [POI2013]BAJ-Bytecomputer

题意

给一个只包含\(-1,0,1\)的数列,每次操作可以让a[i]+=a[i-1],求最少操作次数使得序列单调不降。若无解则输出BRAK

思路

毒瘤出题人alecli!你又找紫题。 --Mercury

  • 结论:最优解中变换之后的数列中的数字只有\(-1,0,1\)。

    • 首先考虑为什么不会出现\(2\)。\(2\)的由来只能是\(1+1=2\),而将当前位置上的\(1\)与前一位上的\(1\)相加既不会改变当前位相对于前一位已经单调不降的事实,同时会提高后面数字的大小要求,所以不使这一位上的\(1\)与前一位上的\(1\)相加显然更优。
    • \(-2\)同理。
    • 对于\(x\geq 3\),既然\(2\)都不会出现,那么\(x\)更不可能出现。
    • 对于\(x\leq -3\),同理。

所以我们可以这样设计状态:设计\(f[i][3]\)表示前\(i\)位单调不下降的情况下尾数为某个数所需要的最少操作数,其中,\(f[i][0]\)表示前\(i\)位单调不下降的情况下尾数为\(-1\)所需要的最少操作数,\(f[i][1]\)表示尾数为\(0\),\(f[i][2]\)表示尾数为\(1\)。

那么从\(f[i-1]\)转移到\(f[i]\)时就可以这么写:

f[1][a[1]+1]=0;
for(int i=2;i<=n;i++)
if(a[i]==-1)//当前位上为-1
{
f[i][0]=min(f[i][0],f[i-1][0]);//上一位是-1,可以不用操作
f[i][2]=min(f[i][2],f[i-1][2]+2);//上一位是1,操作两次把-1变成1
}
else if(a[i]==0)//当前位上为0
{
f[i][0]=min(f[i][0],f[i-1][0]+1);//上一位是-1,操作两次把0变成-1
f[i][1]=min(f[i][1],f[i-1][0]);//上一位是-1,可以不用操作
f[i][1]=min(f[i][1],f[i-1][1]);//上一位是0,可以不用操作
f[i][2]=min(f[i][2],f[i-1][2]+1);//上一位是1,操作一次把0变成1
}
else if(a[i]==1)//当前位上为1
{
f[i][0]=min(f[i][0],f[i-1][0]+2);//上一位是-1,操作两次把1变成-1
f[i][1]=min(f[i][1],f[i-1][0]+1);//上一位是-1,操作一次把1变成0
f[i][2]=min(f[i][2],f[i-1][0]);//上一位是-1,可以不用操作
f[i][2]=min(f[i][2],f[i-1][1]);//上一位是-1,可以不用操作
f[i][2]=min(f[i][2],f[i-1][2]);//上一位是-1,可以不用操作
}

这样转移下去,就能得到答案了。答案在\(f[n][0],f[n][1],f[n][2]\)中选取最小值。

AC代码

#include<bits/stdc++.h>
using namespace std;
int n,ans,a[1000005],f[1000005][3];
int read()
{
int f=1,re=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return f*re;
}
int main()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read();
memset(f,0x3f,sizeof f);
f[1][a[1]+1]=0;
for(int i=2;i<=n;i++)
if(a[i]==-1)
{
f[i][0]=min(f[i][0],f[i-1][0]);
f[i][2]=min(f[i][2],f[i-1][2]+2);
}
else if(a[i]==0)
{
f[i][0]=min(f[i][0],f[i-1][0]+1);
f[i][1]=min(f[i][1],f[i-1][0]);
f[i][1]=min(f[i][1],f[i-1][1]);
f[i][2]=min(f[i][2],f[i-1][2]+1);
}
else if(a[i]==1)
{
f[i][0]=min(f[i][0],f[i-1][0]+2);
f[i][1]=min(f[i][1],f[i-1][0]+1);
f[i][2]=min(f[i][2],f[i-1][0]);
f[i][2]=min(f[i][2],f[i-1][1]);
f[i][2]=min(f[i][2],f[i-1][2]);
}
ans=min(f[n][0],min(f[n][1],f[n][2]));
if(ans!=0x3f3f3f3f) printf("%d",ans);
else printf("BRAK");
///CHECK:
///for(int i=1;i<=n;i++) printf("\n%d %d %d",f[i][0],f[i][1],f[i][2]);
return 0;
}

Luogu P3558 [POI2013]BAJ-Bytecomputer(线性dp)的更多相关文章

  1. Luogu P1541 乌龟棋 【线性dp】

    题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行 N 个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第 N 格是终点,游戏要求玩家控制一个乌龟 ...

  2. 线性dp

    线性dp应该是dp中比较简单的一类,不过也有难的.(矩乘优化递推请出门右转) 线性dp一般是用前面的状态去推后面的,也有用后面往前面推的,这时候把循环顺序倒一倒就行了.如果有的题又要从前往后推又要从后 ...

  3. 洛谷P1140 相似基因(线性DP)

    题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了444种核苷酸,简记作A,C,G,TA,C,G,TA,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. 在一个人类 ...

  4. 线性DP总结(studying

    写在前面 虽然都说线性DP是入门,但我还是今天才开始学 线性DP就是珂以通过线性处理得出答案的一种DP 每一种状态都可以从前面推得,并且推导过程是呈线性的 参考题单(本人现在主要用luogu,所以这些 ...

  5. LightOJ1044 Palindrome Partitioning(区间DP+线性DP)

    问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时 ...

  6. Codeforces 176B (线性DP+字符串)

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...

  7. hdu1712 线性dp

    //Accepted 400 KB 109 ms //dp线性 //dp[i][j]=max(dp[i-1][k]+a[i][j-k]) //在前i门课上花j天得到的最大分数,等于max(在前i-1门 ...

  8. 动态规划——线性dp

    我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...

  9. POJ 2479-Maximum sum(线性dp)

    Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 33918   Accepted: 10504 Des ...

随机推荐

  1. Android开发 QRCode二维码开发第三方框架

    前言 Android开发里二维码开发经常用到,这里简单的介绍下Android开发里的二维码. 最广泛使用的二维码库zxing zxing是最广泛的二维码库各个平台都可以适用它,但是Android平台使 ...

  2. Java 几种队列区别的简单说明

    前言 队列,字面意思就可以明白. 是一种线性的数据暂存与管理工具. 也可以让各种业务功能进行逐个的队列运行. 此篇博客只说明一下Java有几种队列 未阻塞和阻塞队列的区别 未阻塞: 1.未阻塞的队列在 ...

  3. Android开发 navigation入门详解

    前言 Google 在2018年推出了 Android Jetpack,在Jetpack里有一种管理fragment的新架构模式,那就是navigation. 字面意思是导航,但是除了做APP引导页面 ...

  4. Vim: 强大的g

    来源于:http://vim.wikia.com/wiki/Power_of_g 一般格式: :[range]g/pattern/cmd 对range内所有符合pattern的行执行cmd 常见的一些 ...

  5. 最大流——hdu4292(类似poj3281 带间隔的流)

    #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define inf 0x3f3f3f3f ]; int ...

  6. mysql中的字符串截取和替换

    -- 替换 replace(字段名,"需要替换的字符","替换的字符") mysql里replace不支持正则匹配 mysql> set @needRep ...

  7. KVM热添加技术

    1.KVM热添加的种类 硬盘.网卡.内存.cpu 2.KVM热添加硬盘 1.在宿主机上创建硬盘 qemu-img create -f qcow2 /opt/web02_add01.qcow2 10G ...

  8. eclipse-帮助文档

    Eclipse开发环境配置 1.         java环境 安装 本系统使用java6开发,老师使用1.6.0 _45版本开发,如下图所示: “开发工具”目录提供了1.6.0 _45版本32位和6 ...

  9. 网页qq在线交谈

    网页中如何启用QQ交谈 1. 登录QQ, 打开网址:http://shang.qq.com/v3/widget.html 启用QQ通讯组件. 2. 选择组件样式,设置提示语,例如: 3. 刷新页面,C ...

  10. mysql commond record

    CREATE DATABASE IF NOT EXISTS codex_gm DEFAULT CHARACTER SET utf8; service mysqld stop screen -dmS m ...