2076. The Drunk Jailer

Problem

A certain * contains a long hall of n cells, each right next to each other. Each cell has a *er in it, and each cell is locked.

One night, the jailer gets bored and decides to play a game. For round 1 of the game, he takes a drink of whiskey, and then runs down the hall unlocking each cell. For round 2, he takes a drink of whiskey, and then runs down the hall locking every other cell (cells 2, 4, 6, ...). For round 3, he takes a drink of whiskey, and then runs down the hall. He visits every third cell (cells 3, 6, 9, ...). If the cell is locked, he unlocks it; if it is unlocked, he locks it. He repeats this for n rounds, takes a final drink, and passes out.

Some number of *ers, possibly zero, realizes that their cells are unlocked and the jailer is incapacitated. They immediately escape.

Given the number of cells, determine how many *ers escape jail.

Input

The first line of input contains a single positive integer. This is the number of lines that follow. Each of the following lines contains a single integer between 5 and 100, inclusive, which is the number of cells n.

Output

For each line, you must print out the number of *ers that escape when the * has n cells.

Sample Input

2
5
100

Sample Output

2
10



Source: Greater New York 2002

脑子比较笨用的是最北的遍历方法。代码如下:

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 int cell[101];//0表示牢房锁闭,1为打开状态
 5 
 6 int main () 
 7 { 
 8     int n;
 9     scanf("%d",&n);
10     
11     int num;
12     int unlockCount;
13 
14     int i,j;
15 
16     while(n--)
17     {
18         unlockCount=0;
19         memset(cell,0,101*sizeof(int));
20 
21         scanf("%d",&num);
22         for(i=1;i<=num;i++)
23         {
24             for(j=i;j<=num;j+=i)
25             {
26                 if(cell[j] == 0)
27                     cell[j]=1;
28                 else
29                     cell[j]=0;
30             }
31         }
32         for(i=1;i<=num;i++)
33             if(cell[i] == 1)
34                 unlockCount++;
35         printf("%d
",unlockCount);
36     }
37     return 0;
38 }

看到网上还有许多其他解法,一并参考下:

1、转载自:http://blog.csdn.net/sinchb/article/details/8075949

    最笨的方法,就是列一个长度为n的数组代表cell是locked还是unlocked,然后按照游戏方法,遍历n次该数组,不断改变数组中的值,这样时间复杂度是O(n*n)。但是经过观察发现,一个cell被开关的次数其实是有规律的,也就是这个cell的编号n的约数的数量;比如4,他的约数有1,2,4,所以编号为4的cell会在游戏的第1,2,4轮被开/关。又如果一个cell被开/关的最终次数为偶数次,则该cell最终也就是关闭的,这个cell里可怜的*er将无法上演《越狱》,只有cell编号的约数数量为奇数的,才有机会逃跑。所以,问题转换为,求一个数1~n中,有多少数有奇数个约数。
 1 #include <stdio.h>
 2 int main()
 3 {
 4     short unsigned cell[101] = {0,1,1,1,2,2},i = 0,j,top,sum = 0;
 5     int N,n;
 6     for(i = 6;i <= 100;i++)
 7     {
 8         sum = 0;
 9         top = i>>1;
10         for(j = 2;j <= top ;j++)
11             !(i % j) ? sum++ :0;
12         cell[i] = cell[i-1] + sum%2;
13     }
14     scanf("%d",&N);
15     while(N--)
16     {
17         scanf("%d",&n);
18         printf("%d
",cell[n]);
19     }
20     return 0;
21 }

2、转载自:http://zhidao.baidu.com/link?url=4SkSUEHqhMhNniqchgFztGMNMemf8zP-UgP_ZTVE4TqAqfIGYF-UM8z4m_wHaoOhJLC-ILQUGk5ofRY2GfNEEK

代码比较简洁

编号为1的门只为1的倍数,所以只执行了一次操作,所以其最后的状态是开,编号为2的门只为1和2的倍数,执行了两次操作,其最后的状态是关,编号为3的门为1和3的倍数,执行了三次操作,其最后的状态为关,编号为4的门为1、2、4的倍数,执行了三次操作,其最后的状态为开......以此类推,如果编号为一个数的平方数,则其执行操作的次数为奇数次,其最后的状态为开。于是只要求出小于这个数的正整数中有几个数是平方数即可。

 1 #include<stdio.h>
 2 #include<math.h>
 3 int main(void){int n, a, on;
 4     scanf("%d",&n);
 5     while(n--){
 6         scanf("%d",&a);
 7         on=(int)sqrt(a);
 8         printf("%d
",on);
 9     }
10     return0;
11 }