把三类操作统一成翻倍数,按人只翻 k,2k,3k,… 模拟,输出被翻奇数次的灯。
OJ: roj
题目 ID: 1109
难度:入门
标签:模拟数论
创建: 2026-09-29 19:15
更新: 2026-10-05 01:40
题目描述
有 10 10,输出 1,4,9。
思路
初始全亮让三类操作统一为“第
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 19:15
# update_at: 2026-09-29 19:15
import sys
def solve() -> None:
n, m = map(int, sys.stdin.buffer.read().split())
# off[j] = 1 表示灯 j 被翻过奇数次(初始全亮,翻奇数次即最终关闭)。
# 1 号"全部关闭"、2 号"打开 2 的倍数"本质都是取反,统一按翻倍数处理。
off = bytearray(n + 1)
for d in range(1, m + 1):
off[d::d] = bytes(v ^ 1 for v in off[d::d]) # 下标 d, 2d, 3d, ... 恰是 d 的倍数
print(','.join(map(str, (j for j in range(1, n + 1) if off[j]))))
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-05 01:40
* update_at: 2026-10-05 01:40
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5005;
int n, m;
// off[j] = 1 表示灯 j 被翻过奇数次(初始全亮,翻奇数次即最终关闭)。
int off[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
if (!(cin >> n >> m)) return 0;
// 1 号"全部关闭"、2 号"打开 2 的倍数"、k>=3 号"取反 k 的倍数",
// 三类操作在"初始全亮"下都等价于:把该人编号的倍数翻转一次。
// 循环直接落在倍数上,省掉 j % k == 0 的逐灯判断。
for (int d = 1; d <= m; d++) {
for (int j = d; j <= n; j += d) {
off[j] ^= 1;
}
}
bool first = true;
for (int j = 1; j <= n; j++) {
if (off[j]) {
if (!first) cout << ',';
cout << j;
first = false;
}
}
cout << '\n';
return 0;
}