美团8.19第三题-01权值

我看到大家好像都是用动态规划, 没有用位操作的. s 只可能翻转成两种序列:

  • 101010
  • 010101

并且注意到, s 与这两种序列做异或, 得到 1 的个数就是转为对应序列的操作数, 两个中取最小值则是权值. 即:

  • 10001 ^ 10101 = 00100
  • 10001 ^ 01010 = 11011

使用 BitSet将 s 与这两种序列做异或, 对应区间 1 的个数就为对应区间的权值. 也可以使用前缀和, 这样查询就是 `O(1)`

public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String s = in.nextLine();

            int n = s.length();
            long res = 0;

            BitSet b = new BitSet(n); // 原始序列
            BitSet b1 = new BitSet(n); // 101010序列
            BitSet b2 = new BitSet(n);// 010101序列
            for (int i = 0; i < n; i++) {
                int num = s.charAt(i) - '0';
                if (num == 1) {
                    b.set(i);
                }

                int n1 = i % 2;
                if (n1 == 1) {
                    b1.set(i);
                }

                int n2 = (i + 1) % 2;
                if (n2 == 1) {
                    b2.set(i);
                }
            }
            // 异或
            b1.xor(b);
            b2.xor(b);

            for (int i = 0; i <= n - 2; i++) {
                for (int j = i+1; j < n; j++) {
                    // 查询对应区间的 1, 也可使用前缀和
                    int i1 = b1.get(i, j+1).cardinality();
                    int i2 = b2.get(i, j+1).cardinality();

                    res += Math.min(i1, i2);
                }
            }

            System.out.println(res);
        }
    }

全部评论
优雅dp过了依旧学习
2 回复 分享
发布于 2023-08-19 23:21 广东
😂第一时间想到的也是异或 但是c++不知道怎么操作 索性就一位一位的比较了
点赞 回复 分享
发布于 2023-08-19 23:42 广东

相关推荐

评论
1
10
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务