題目描述:
定義一個函數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,若當前數字不是幸運數,那當前幸運數個數與它前一個數字的幸運數個數相等。