题目描述
走廊上有n个储物柜,从1到n依次编号。最初,所有的储物柜门都关闭了。你经过储物柜,每次从储物柜#1开始。在第 i 次传递中,i = 1, 2, ..., n,你切换每个第 i 个储物柜的门:如果门是关闭的,你打开它,如果它是打开的,你关闭它。例如,在第一次通过后,每扇门都打开;在第二遍中,您只切换偶数储物柜(#2、#4、...),以便在第二遍后偶数门关闭并打开奇数门;第三次通过你关闭储物柜#3的门(从第一次通过打开),打开储物柜#6的门(从第二次通过关闭),依此类推。在最后一次通过后,哪些储物柜门打开,哪些关闭?其中有多少是开放的? 你的任务是编写一个程序来输出 最后一次通过后打开了多少扇门?假设所有的门一开始都是关闭的。
题目意思:有n的储物柜,起初每扇门都是关闭的,在第一次经过的时候打开所有门;第二次经过的时候关闭偶数门,此时开着的只有奇数门;第三次经过的时候对是3的倍数的门的编号进行操作(开着的关闭,关着的打开)依次类推,最后一次即为第n次。
ps:oj题目表述意思真的很迷,我看了很久也没看出来题目中有体现是在第二次操作以后,每个第i次操作只需要对是i的倍数的编号的门进行开关就行.......
输入
a positive numbers n, total doors. n<=100000 (一个正数n,门的总数)
输出
a positive numbers ,the total of doors opened after the last pass. (一个正数,最后一次通过后打开了多少扇门)
样例输入复制
10
样例输出复制
3
样例分析:
方法一:如果你继续往后写,发现的规律就是,从1到n的数中开根号为整数的,就是最后一次通过后仍然打开的门的编号。
ps:之前看到过一个评论说的是:如果我们把每扇门的位置当成一个数,那么这道题就是求每个数的因数个数,如果它的因数个数是奇数个,那么最终这扇门就是开着的(与初始门的状态相反),反之,如果这扇门因数个数是偶数个,那么这扇门最终就是关着的。而函数表达的比输入数小的奇数和(通过等差数列求和公式你会发现就是判断一个数是否为平方数)。而一个数的因数是奇数个,那么这个数就一定是平方数。因此可用此方法.
具体代码如下:
#include<iostream>
#include<math.h>
using namespace std;
int main() {
int n;
cin >> n;
int cnt = 0;
for (int i = 1; i <=sqrt(n); i++) {
if (i * i <= n)cnt++;
}
cout << cnt << endl;
}
方法二:
如果没有发现上述规律,也可以用遍历来写。(思路还是简单的,循环实现就行,代码我还没写,先欠着。。。。。。)
两个for循环,第一层是次数,第二层就是每次对1-n的数进行判断,用数组存,如果是i的倍数且小于等于n就标记为1,即是打开。循环到最后一次。再来一个for循环,数组为1的就cnt++.时间复杂度是O(n2)比较高。