四个按钮只关心奇偶共 16 种组合,按钮作用以 6 为周期,枚举前 6 盏灯的翻转图案并用最少按压次数与 C 同奇偶判定可行性。
OJ: roj
题目 ID: 2029
难度:普及
标签:枚举位运算周期性
创建: 2026-10-01 03:44
更新: 2026-10-06 09:51
题目描述
-1 结束),求所有满足约束的最终状态(1 亮 0 灭),按二进制从小到大输出;无解输出 IMPOSSIBLE。
思路
同一个按钮按两次等于没按,故只需考虑四个按钮各按
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 03:44
# update_at: 2026-10-01 03:44
import sys
from collections.abc import Iterator
from itertools import product
# 同一个按钮按两次等于没按,所以每个按钮只需考虑按 0/1 次,共 16 种奇偶组合;
# 又因奇数灯归按钮 2、偶数灯归按钮 3、3k+1 灯归按钮 4,各按钮的覆盖范围
# 以 6 为周期重复,所以整个结局只由"前 6 盏灯的翻转图案 + 总按压次数的奇偶"决定。
BUTTONS = tuple(product((0, 1), repeat=4)) # (按钮1, 按钮2, 按钮3, 按钮4) 各按 0/1 次
def flip_pattern(presses: tuple[int, ...]) -> int:
"""一组按钮奇偶对前 6 盏灯的翻转图案:第 k 位为 1 表示第 k+1 盏灯被翻转。"""
p1, p2, p3, p4 = presses
mask = 0
for k in range(6):
# 灯 k+1 受按钮 2/3 之一(看灯号奇偶)与按钮 4(灯号是 3k+1)共同作用
if p1 ^ (p2 if k % 2 == 0 else p3) ^ (p4 if k % 3 == 0 else 0):
mask |= 1 << k
return mask
# 16 种奇偶组合的图案两两不同(由图案可反解出 p2、p3、p4 和 p1),
# 于是每种图案对应唯一的最少按压次数 = 四个按钮按压次数之和。
STATES = sorted((sum(presses), flip_pattern(presses)) for presses in BUTTONS)
def lamp_set(tokens: Iterator[int]) -> set[int]:
"""读到哨兵 -1 为止的一组灯号。"""
lamps: set[int] = set()
while (lamp := next(tokens)) != -1:
lamps.add(lamp)
return lamps
def lamp_state(pattern: int, lamp: int) -> int:
"""灯 lamp 的最终状态:初始全亮,被翻转过则变 0。"""
return 1 ^ (pattern >> (lamp - 1) % 6 & 1)
def solve() -> None:
tokens = iter(map(int, sys.stdin.buffer.read().split()))
n, c = next(tokens), next(tokens)
on, off = lamp_set(tokens), lamp_set(tokens)
rows = sorted({
''.join(str(lamp_state(pattern, lamp)) for lamp in range(1, n + 1))
for min_press, pattern in STATES
# 恰好按 c 次:先够到最少次数,剩下的次数两两成对补进任意按钮
if min_press <= c and (c - min_press) % 2 == 0
# 亮灯与灭灯约束全部满足
if all(lamp_state(pattern, lamp) == 1 for lamp in on)
if all(lamp_state(pattern, lamp) == 0 for lamp in off)
})
print('\n'.join(rows) if rows else 'IMPOSSIBLE')
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 09:51
* update_at: 2026-10-06 09:51
*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long ll;
int n, c;
int on_lamps[105], off_lamps[105]; // 存储亮灯与灭灯约束
int on_cnt, off_cnt;
// 16 种奇偶组合对应的最少按压次数与前 6 盏灯的翻转图案(6 位二进制)
struct State {
int press; // 最少按压次数
int pattern; // 前 6 盏灯的翻转图案,第 k 位为 1 表示第 k+1 盏灯被翻转
};
State states[16];
int state_cnt;
// 计算一组按钮奇偶对前 6 盏灯的翻转图案
int calc_pattern(int p1, int p2, int p3, int p4) {
int mask = 0;
for (int k = 0; k < 6; k++) {
int flip = p1;
if (k % 2 == 0) flip ^= p2; // 奇数号灯(k=0 对应灯号 1)
else flip ^= p3; // 偶数号灯
if (k % 3 == 0) flip ^= p4; // 3k+1 号灯(k=0,3 对应灯号 1,4)
if (flip) mask |= 1 << k;
}
return mask;
}
// 预处理 16 种奇偶组合
void init_states() {
state_cnt = 0;
for (int p1 = 0; p1 <= 1; p1++)
for (int p2 = 0; p2 <= 1; p2++)
for (int p3 = 0; p3 <= 1; p3++)
for (int p4 = 0; p4 <= 1; p4++) {
states[state_cnt].press = p1 + p2 + p3 + p4;
states[state_cnt].pattern = calc_pattern(p1, p2, p3, p4);
state_cnt++;
}
}
// 获取第 lamp 盏灯(1-based)的最终状态:初始全亮,被翻转则为 0
int lamp_state(int pattern, int lamp) {
int pos = (lamp - 1) % 6;
int flipped = (pattern >> pos) & 1;
return 1 ^ flipped;
}
// 检查某个图案是否满足所有亮灯与灭灯约束
bool check(int pattern) {
for (int i = 0; i < on_cnt; i++)
if (lamp_state(pattern, on_lamps[i]) != 1) return false;
for (int i = 0; i < off_cnt; i++)
if (lamp_state(pattern, off_lamps[i]) != 0) return false;
return true;
}
// 生成长度为 n 的灯状态字符串
string build_str(int pattern) {
string s;
s.resize(n);
for (int i = 1; i <= n; i++)
s[i - 1] = '0' + lamp_state(pattern, i);
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
init_states();
cin >> n >> c;
on_cnt = 0;
while (true) {
int x;
cin >> x;
if (x == -1) break;
on_lamps[on_cnt++] = x;
}
off_cnt = 0;
while (true) {
int x;
cin >> x;
if (x == -1) break;
off_lamps[off_cnt++] = x;
}
vector<string> ans;
for (int i = 0; i < state_cnt; i++) {
int press = states[i].press;
int pattern = states[i].pattern;
// 恰好按 c 次:最少次数不超过 c,且差值为偶数(多出来的次数成对抵消)
if (press > c || (c - press) % 2 != 0) continue;
if (!check(pattern)) continue;
ans.push_back(build_str(pattern));
}
sort(ans.begin(), ans.end());
ans.erase(unique(ans.begin(), ans.end()), ans.end());
if (ans.empty()) {
cout << "IMPOSSIBLE\n";
} else {
for (size_t i = 0; i < ans.size(); i++)
cout << ans[i] << "\n";
}
return 0;
}