Codeforces1547D Co-growing Sequence (构造 贪心 位运算)

题目链接: Co-growing Sequence

大致题意

定义:

  1. 一个长度为n的序列a, 如果满足 a[i] & a[i + 1] == a[i], i ∈ [1, n), 则称该序列为增长的

  2. 两个长度均为n的序列a, b. 现构造出长度为n的序列c, 使得 c[i] = a[i] ⊕ b[i], i ∈ [1, n], 若c序列是增长的, 则称序列a和b是同增的

现给出序列a, 让你构造出一个字典序最小的序列b, 使得a和b是同增的.

解题思路

我们首先对增长的序列进行分析:

如果a[i] & a[i + 1] == a[i], 则表明a[i]二进制位为1的位置, a[i + 1]在该位上也要为1.


考虑到题中需要我们构造的序列b, 相当于我们可以修改a[i], 使其变为c[i]后, 让c序列变为增长的序列.
相当于a[i] & a[i + 1] == a[i], 变为: (a[i] ⊕ b[i]) & (a[i + 1] ⊕ b[i + 1]) == a[i] ⊕ b[i] <==> c[i] & c[i + 1] == c[i].

由于b序列要求字典序最小, 因此最初i = 1时, 我们令b[1] = 0, 找到最小的b[2]一定最优的. 当i = 2时, 此时b[2]的值确定了, 相当于c[2]确定了, 此时我们找到最小的b[3]一定最优. 以此类推……

我们发现, 由于每次我们都是找到最小的b[i + 1]最优, 因此我可以将上式改写为: c[i] & (a[i + 1] ⊕ b[i + 1]) == c[i], 其中c[i], a[i + 1]都是确定的.

因此题目等价于: 我们找到最小的b[i + 1], 使得temp = a[i + 1] ⊕ b[i + 1], 满足c[i]二进制位为1的位置, temp在该位上也为1. (文段最开头提到了)

我们考虑如何找到这个temp值. 提取模型 x & (y ⊕ z) == x 找到最小的z

这相当于, 使得 (y ⊕ z) == x | y     等价于     z = (x | y) ⊕ y


为什么呢?

我们对于每一位来考虑:
​ ①如果x和y本身这一位上相同, 则z这一位上取0即可.
​ ②如果这一位不相同: 如果x是0, y是1, 则z这位取0; 反之若x是1, y是0, 则z这位取1.

分析可得: z的作用本质是把x为1的位置, y为0的位置变为1. 至于其余的情况, 都无需考虑. 而(x | y) ⊕ y刚好就做了这样的事情.

因此取b[i + 1] = (c[i] | a[i + 1]) ^ a[i + 1]即可.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 2E5 + 10;
int a[N], b[N];
int main()
{
	int t; cin >> t;
	while (t--) {
		int n; scanf("%d", &n);
		rep(i, n) scanf("%d", &a[i]);

		rep(i, n) { // 代码中, a序列与c序列共用了a[]数组, a[j]即为c[j], j < i.
			b[i] = (a[i - 1] | a[i]) ^ a[i]; 
			a[i] ^= b[i]; //把a[i]变为c[i]
		}

		rep(i, n) printf("%d%c", b[i], " \n"[i == n]);
	}
	
	return 0;
}

END

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值