Description
n盏灯排成一排,从1到n按顺序依次编号。有n个人也从1到n依次编号。第一个人(1号)将灯全部关闭。第二个人(2号)将凡是2和2的倍数的灯打开。第三个人(3号)将凡是3和3的倍数的灯作相反处理(该灯如为打开的将其关闭;如为关闭的,将其打开)。以后的人都和三号一样,将凡是与自己相同的灯和是自己编号倍数的灯作相反处理。请问,当第n个人操作之后,从第A盏灯跟第B盏灯之间(包含AB两盏),有多少灯是开着的?
Input
N,A,B(A<B<N<10^7)
Output
从A到B(包含AB)开着的灯的数目
Sample Input
5 1 3
5 1 3
Sample Output
2
解法一:
初看到这个题,我的思路是从人的角度出发的。即设置两层循环,外循环为灯,内循环为人,每来一个人则将他的序号和序号倍数的灯的状态改变一次(0为关,1为开)。最后再用count记录一下1的个数。但是,在改变灯的状态时,我最开始用的是“~”,但是我忽略了1的二进制前面的0,认为~1=0。后来我用异或代替取反,求解出了答案。代码如下
<span style="font-size:14px;">#include<iostream>
#include<string.h>
int l[10000000] ;
using namespace std;
int main()
{
int light,n1,n2,count=0;
cin>>light>>n1>>n2;
memset(l,0,n2);
for(int i=2;i<=n2;i++)
{
for(int j=1;j<=light;j++)
{
if(j%i==0)
{
l[j]=l[j]^1;
}
}
}
for(int i=1;i<=n2;i++)
{
if(l[i]==1)
count++;
}
cout<<count<<endl;
return 0;
}</span><div>
</div>
但这种方法每来一个人都要判断所有的灯,因此可以用每个人的序号作步长,这样就可以减少判断的次数。
解法二:
从灯的角度来说,如果灯的开关次数是偶数,则最终灯是亮着的,如果是奇数是关着的。我们只需判断灯的因子是奇数还是偶数即可。完全平方数的因子是奇数,题目就简化为了判断灯序号是不是完全平方数了。代码如下
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
int light,n1,n2,count=0;
cin>>light>>n1>>n2;
for(int i=n1;i<=n2;i++)
{
int x=(int)sqrt(i);
if(x*x!=i)
count++;
}
cout<<count<<endl;
return 0;
}