P1876开灯
题目描述
首先所有的灯都是关的(注意是关!),编号为1的人走过来,把是一的倍数的灯全部打开,编号为二的的把是二的倍数的灯全部关上,编号为3的人又把是三的倍数的灯开的关上,关的开起来……直到第N个人为止。
给定N,求N轮之后,还有哪几盏是开着的。
输入格式
一个数N,表示灯的个数和操作的轮数
输出格式
若干数,表示开着的电灯编号
输入输出样例
输入
5
输出
1 4
说明/提示
1<=N<=2^40
分析:根据题目意思,我们可以简单模拟走一遍,找一下规律。
我们就以样例举例,假设N为1-5,由于灯的开关是非开即关的操作。可以用0,1来表示灯的状态。
灯编号:1 2 3 4 5…n
第零步:0 0 0 0 0 --题意,开始全部为关闭状态
第一步:1 1 1 1 1 --把是一的倍数的灯全部打开
第二步:1 0 1 0 1 --对2的倍数的灯进行操作(打开或关闭)
第三步:1 0 0 0 1 --同理…
第四步:1 0 0 1 0 -----…
不难看出当n为1,2,3,4,5时,开着的灯的编号为1,1,1,(1,4)(1,4)。
那么,由此可以发现什么端倪?
先引入一点简单的数学概念:非完全平方数与完全平方数:
非完全平方数:因数个数肯定为偶数个
完全平方数:因书个数为奇数个
接下来,进一步观察上面模拟演示的结果,你会发现,本题的本质,其实就是寻找因素为奇数个的数,如何打印。而含有该特征的数,明显是平方数(请细思慢品…)。
所以,接下来要做的,就是寻找n以内的平方数。
知道了规律,coding起来就相对比较容易了。
演示C++版本:
#include<iostream>
#include<string>
using namespace std;
int main(){
long long n;
cin>>n;
for(int i=1;i*i<=n;i++)
{
cout<<i*i<<" ";
}
return 0;
}
结果示例: