题目描述:
定义一个函数f(x)表示x这个数用十进制写出各个数位的数字之和,比如:f(123) = 1 + 2 + 3 = 6;定义一个函数g(x)表示这个数用二进制写出各个位数上的数字之和,比如:123用二进制表示为1111011,那么g(1111011) = 1 + 1 + 1 + 1 + 0 + 1 + 1 = 6。若有一个数x有f(x) = g(x),则说明这个数是幸运数。若给定一个范围n,求小于等于n的幸运数有多少个。
输入:第一行一个整数T(T<=10000)表示数据组数,每组数据输入一个数n(n <= 100000)。
输出:每组数据输出一行,小于等于n的幸运数个数。
样例输入:
3
1
5
21
样例输出:
1
1
3
我写的程序如下:
#include <iostream>
using namespace std;
int f(int n)
{
int sum = 0;
while(n)
{
sum += n % 10;
n /= 10;
}
return sum;
}
int g(int n)
{
int sum = 0;
while(n)
{
sum ++;
n = n % (n - 1);
}
return sum;
}
int main(void)
{
int T;
while (cin >> T)
{
while (T--)
{
int n;
cin >> n;
int cnt = 0;
for (int i = 1; i <= n; ++i)
{
if (f(i) == g(i))
cnt ++;
}
cout << cnt << endl;
}
}
return 0;
}
可是将这种暴力做法上传上去发现,用例一个都没跑出来,运行超时。
下来之后,上网查还有没有更好的方法,看到网友的讨论说这样暴力做法重复的运算太多了,如果将运算后的结果保存下来,就大大节省了时间,说的好有道理。算法修改为先一口气算完1~100000所有的数的幸运数,之后每次输入一个数,直接查找数组即可获得答案。算法修改如下:
#include <iostream>
#include <vector>
using namespace std;
int f(int n)
{
int sum = 0;
while(n)
{
sum += n % 10;
n /= 10;
}
return sum;
}
int g(int n)
{
int sum = 0;
while(n)
{
sum ++;
n = n & (n - 1);
}
return sum;
}
int main(void)
{
vector<unsigned long long> ans(100001, 0);
for (unsigned int i = 1; i < 100001; ++i)
{
if (f(i) == g(i))
{
ans[i] = 1 + ans[i - 1];
}
else
{
ans[i] = ans[i - 1];
}
}
int T;
while (cin >> T)
{
int n;
while (T--)
{
cin >> n;
cout << ans[n] << endl;
}
}
return 0;
}
定义的一个ans数组,用来存放1~100000所有数字从1到该数字的幸运数个数,之后直接从ans数组中取出答案。逻辑是:若当前数字是幸运数,那它前边的总幸运数加1,若当前数字不是幸运数,那当前幸运数个数与它前一个数字的幸运数个数相等。