zoukankan      html  css  js  c++  java
  • 洛谷 P3558 [POI2013]BAJ-Bytecomputer

    被一篇我自认为写的挺好的题解给搞蒙了。
    然后急中生智发现他写的很多状态都很冗余,改简洁之后就理解了

    思路

    挺神的一道线性 ( ext{DP}) 题。

    发现最后的序列也是 (-1,0,1) 序列,因为改为别的值花费一定会变得更多。

    (f_{i,j}) 表示前 (i) 个数字已经排好,第 (i) 个数字变为 (j) 的方案数,但是显然不能用负数下标,所以定义可以有一些修改。设 (f_{i,j}) 表示前 (i) 个数字已经排好,第 (i) 个数字变为 (j-1) 的方案数,那么能够用的数就是 (f_{i,0},f_{i,1},f_{i,2}),分别表示当前数为 (-1,0,1) 时的情况。

    初始化整个 (f) 数组为 (inf),并且初始化 (f_{1,a_1+1}=0),因为第一个数为 (a_1) 的方案数显然为 (0)

    然后分情况讨论:

    • (a_i=-1) 时:

      1. 变为 (-1) 的方案数:因为当前数已经是 (-1) 了,所以 (f_{i,0}=f_{i-1,0})
      2. 变为 (0) 的方案数:如果要让 (-1) 变成 (0),前一个数必须是 (1),如果要 (a_{i-1}) 转化为 (1),那么当前数也必须是 (1),这样的话当前数就不能为 (0) 了,也就是说不能有 (f_{i,1}) 了,所以(f_{i,1}=inf)
      3. 变为 (1) 的方案数:同上,如果要让 (-1) 变成 (1),前一个数必须是 (1),转移次数为 (2),所以此时的方案数为 (f_{i,2}=f_{i-1,2}+2)
    • (a_i=0) 时:

      1. 变为 (-1) 的方案数:只能从上一个数变为 (-1) 的方案转移过来,转移次数为 (1),即 (f_{i,0}=f_{i-1,0}+1)
      2. 变为 (0) 的方案数:当前数已经为 (0) 了,上一个数是 (-1,0) 都行,所以取上一个数两个方案数中的最小值即可,即 (f_{i,1}=min(f_{i-1,0},f_{i-1,1}))
      3. 变为 (1) 的方案数:同 (a_i=-1) 时的情况,之不管转移次数变成了 (1), 如果要让 (0) 变成 (1),那么前一个数需要是 (1),所以 (f_{i,2}=f_{i-1,2}+1)
    • (a_i=1) 时:

      1. 变为 (-1) 的方案数:只能从上一个数变为 (-1) 的方案转移过来,转移次数为 (2),即 (f_{i,0}=f_{i-1,0}+2)
      2. 变为 (0) 的方案数:前一个数必须是 (-1) 才能变成 (0),所以 (f_{i,1}=f_{i-1,0}+1)
      3. 变为 (1) 的方案数:当前数已经为 (1) 了,上一个数是什么都行,所以直接取上一个数三个方案数中的最小值即可,即 (f_{i,2}=min(f_{i-1,0},f_{i-1,1},f_{i-1,2}))

    综上转移方程汇总:

    [ ext{if } a_i=-1egin{cases}f_{i,0}=f_{i-1,0}\f_{i,1}=inf\f_{i,2}=f_{i-1,2}+2end{cases} ]

    [ ext{if }a_{i}=0egin{cases}f_{i,0}=f_{i-1,0}+1\f_{i,1}=min(f_{i-1,0},f_{i-1,1})\f_{i,2}=f_{i-1,2}+1end{cases} ]

    [ ext{if }a_{i}=1egin{cases}f_{i,0}=f_{i-1,0}+2\f_{i,1}=f_{i-1,0}+1\f_{i,2}=min(f_{i-1,0},f_{i-1,1},f_{i-1,2})end{cases} ]

    最后的答案显然就是 (f_{n,0},f_{n,1},f_{n,2}) 中的最小值。

    注意要判断无解情况

    时间复杂度 (O(n))

    代码

    //*
      Time: 18/09/20 15:26
      Author: Loceaner
      Description: 线性DP 
    */
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 1e6 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int n, a[A], f[A][3];
    
    signed main() {
      n = read();
      for (int i = 1; i <= n; i++) a[i] = read();
      memset(f, inf, sizeof(f));
      f[1][a[1] + 1] = 0;
      for (int i = 2; i <= n; i++) {
        if (a[i] == -1) {
          f[i][0] = f[i - 1][0];
          f[i][2] = f[i - 1][2] + 2; 
        }
        if (a[i] == 0) {
          f[i][0] = f[i - 1][0] + 1;
          f[i][1] = min(f[i - 1][0], f[i - 1][1]);
          f[i][2] = f[i - 1][2] + 1;
        }
        if (a[i] == 1) {
          f[i][0] = f[i - 1][0] + 2;
          f[i][1] = f[i - 1][0] + 1;
          f[i][2] = min(min(f[i - 1][0], f[i - 1][1]), f[i - 1][2]);
        }
      }
      int ans = min(min(f[n][0], f[n][1]), f[n][2]);
      if (ans == inf) cout << "BRAK
    ";
      else cout << ans << '
    ';
      return 0;
    }
    
  • 相关阅读:
    springmvc整合mybatis框架源码 bootstrap
    观察者模式与.Net Framework中的委托与事件
    C#类型基础——学习笔记一
    知识图谱简介及常见应用场景
    Go语言实现bitmap算法
    互联网公司不同发展阶段需要什么样的技术负责人
    Go语言中使用切片(slice)实现一个Vector容器
    Go语言中defer语句使用小结
    使用interface与类型诊断机制判断一个类型是否实现了某个方法
    互联网产品发掘种子用户和意见领袖的方法
  • 原文地址:https://www.cnblogs.com/loceaner/p/13692720.html
Copyright © 2011-2022 走看看