TopCoder 12792 BitwiseAnd 题解
题意
给
求字典序最小的
做法
先转成二进制,然后条件就等价于对于每一个二进制位,
那么我们将
枚举
- 如果
已经不为 ,就不考虑下面的了。 - 如果
且 ,那么无解。(因为都修改不了) - 如果
,那么 修改不了,只有从 下手。如果 中有二进制位只在 出现过一次,那么可以让这一位在 也出现一次。如果有多个这样的二进制位,取最小的。(因为要字典序最小) - 否则(
)分两种情况:- 如果
有二进制位只在 出现过一次,那么让它在 中出现。多个取最小。(因为要字典序最小) - 否则,取以下两种情况中
较小的:- 如果有二进制位只在
中出现,那么让它在 中出现。多个取最小。 - 如果有一个二进制位没有出现过,那么让它在
和 中都出现。
- 如果有二进制位只在
- 如果
看不懂?伪代码版解释:
将只在
将没有出现过的最小的
证明不难(贪心),当作业。
代码
#include <cstdio>
#include <algorithm>
#include <vector>
using std::vector;
typedef long long LL;
const int N = 50 + 5;
int edge[N][N];
int used[70];
vector<int> to[N];
int nw_id() {
for(int i = 0; i < 60; i++) if(!used[i]) return i;
return -1;
}
LL ans[N];
class BitwiseAnd {
public:
vector<LL> lexSmallest(vector<LL> st, int n) {
int m = st.size();
for(int i = 1; i <= m; i++) ans[i] = st[i - 1];
for(int i = 1; i <= m; i++)
for(int j = 0; j < 60; j++) if(st[i - 1] >> j & 1) {
if(!used[j]) used[j] = i;
else if(used[j] != -1) edge[i][used[j]] = edge[used[j]][i] = true, used[j] = -1;
else return {};
}
for(int i = 59; i >= 0; i--) if(used[i] > 0) to[used[i]].push_back(i);
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++) if(!edge[i][j]) {
if(i <= m && j <= m) return {};
else if(i <= m) {
if(to[i].empty()) return {};
int id = to[i].back();
to[i].pop_back();
ans[j] |= 1LL << id;
used[id] = -1;
} else {
int id;
if(!to[i].empty()) id = to[i].back(), to[i].pop_back();
else {
id = 100;
if(to[i].empty() && to[j].empty()) id = std::min(id, nw_id());
if(!to[j].empty()) id = std::min(id, to[j].back()), to[j].pop_back();
}
if(id == -1 || id == 100) return {};
ans[i] |= 1LL << id, ans[j] |= 1LL << id;
used[id] = -1;
}
}
auto v = vector<LL>(ans + 1, ans + n + 1);
std::sort(v.begin(), v.end());
return v;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】