//
//现在有编号为1~n的灯初始状态是全开着的,
//现进行如下操作:
//编号是1的倍数的灯拨一下开关;
//编号是2的倍数的灯再拨一下开关;
//编号是3的倍数的灯再拨一下开关;
//…………
//如此直到n的倍数。
//问:此时还有多少盏灯仍然是开着的
常规解法:
(1)数组n个位置标识灯的状态 然后按操作一次次更新灯的状态;最后数组里统计
(2)分析下 n的倍数肯定是要比n大的,所以操作n倍数的时候 1~n-1的灯状态是不会再变化了 即f(n-1) 值固定了
只要再运算下第n灯 n次操作后是否开的; f(n)=f(n-1) + (第n灯开?1:0)
//递归写法简单
//可性能差 只适合小数
#include <iostream>
using namespace std;
int getLampOnNumber(int n)
{
if (n == 1) {
return 0;
}
int iCount = 1; //初始开 1
for (int i=1; i<=n; i++) {
if (n % i == 0) {
iCount++;
}
}
return getLampOnNumber(n-1)+(iCount%2);
}
int main()
{
int n;
cin >> n ;
cout << getLampOnNumber(n) << endl;
return 0;
}
//递推比递归性能快
//可性能还是很差 只适合小数
#include <iostream>
using namespace std;
int getLampOnNumber(int n)
{
int s = 0;//亮灯总数
for(int i=1;i<=n;i++)
{
int iCount = 0;//初始开为1 但全部为1的倍数 所以初始化为关0 循环即可从2开始
for (int j=2; j<=i; j++) {
if (i % j == 0) {
iCount++;
}
}
s += (iCount%2);
}
return s;
}
int main()
{
int n;
cin >> n ;
cout << getLampOnNumber(n) << endl;
return 0;
}
(3)在 f(n)=f(n-1) + (第n灯开?1:0)基础上可在判断第n灯的状态代码再优化;操作上可知 第n灯只有到n的约数时候 第n灯才会被操作,因此问题可转为求 n 的约数个数
// 初始开 n的约数个数为偶数 开
// 奇数 关
// 一个整数的约数总是成对出现的
// 只有完全平方数的约数是奇数例如16 约数 1 16 2 8 4
#include <iostream>
#include "time.h"
#include <cmath>
using namespace std;
int main()
{
int n;
cin >> n ;
cout << n-(int)sqrt(n) << endl;
//cout << getLampOnNumber(n) << endl;
return 0;
}
//约数个数 函数
int getDivisorNum(int n)
{
if( n < 1)
return 0;
//vector<int> vDivisor;
int s = 1;
int num = (int)sqrt(n);
for(int i=2;i<=num;i++)
{
int iCount = 1;
while(n%i == 0)
{
iCount++;
n /= i;
}
s *= iCount;
}
if( n > 1 )
s *= 2;
return s;
}