[UVa] 10994 - Simple Addition
題目
時間限制: 3秒
輸入: int, int
$$
\begin{align*}
F(n) = \left\{ \begin{array}{cc}
n\%10 ,& \hspace{5mm} if\quad(n\%10)>0 \\
0,& \hspace{5mm} if \quad n=0 \\
F(n/10),& \hspace{5mm} Otherwise \\
\end{array} \right.
\end{align*}
$$
$$
S(p,q) = \sum_{i=p}^{q} F(i)$$
輸入: int, int
輸入兩個整數 p, q 然後計算出 S(p, q) 的值
$$
\begin{align*}
F(n) = \left\{ \begin{array}{cc}
n\%10 ,& \hspace{5mm} if\quad(n\%10)>0 \\
0,& \hspace{5mm} if \quad n=0 \\
F(n/10),& \hspace{5mm} Otherwise \\
\end{array} \right.
\end{align*}
$$
$$
S(p,q) = \sum_{i=p}^{q} F(i)$$
解題思維
最直觀的想法為用迴圈從 F(s) 不斷的累加直到 F(q) ,不過這樣會超過題目要求的時間。
稍微想下後發現,F(n)的值都介於 0~9 之間
因此可以把F(n)的數列看成這樣:
(0、1、2 ... 8、9)、F(10)、(1 、2 ... 8、9)、F(20) ... (1、2 ... F(n))
然後根據函示 F(n) 的定義如果 n 可以被 10 整除,則 F(n) = F(n/10)
再把上面的式子化簡成下面這樣:
(0、1、2 ... 8、9)、F(1)、(1 、2 ... 8、9)、F(2) ... (1、2 ... F(n))
整理後這樣題目就好解多了!
再來寫一個計算等差級數總和的函式
接下來寫一個函式計算 S(p, q)
先把結尾是 (1~9) 的數字做一個間隔來切割,如下:
0、(1、2 ... 9)、10、(11、12 ... 19)、20、(21、22 ... 29) ...
如果 p 跟 q 在同一個區間的話則直接累加
若 p 、q 在不同區間的話,先把不能湊成一個完整區間的數字累加起來。
ex:
(8、9)、10、(11、12 ... 18 、 19)、20、(21、22、23)
=> 10、(11、12 ... 18 、 19)、20 為一個完整的區間
=> (8、9) 、 (21、22、23) 不是完整的區間
讓 F(p) 一直累加到 9,並更新 p 的位置到還沒運算的地方
在來用 p、q 來計算之間有幾個間隔,在乘上每個間隔中的總和
稍微想下後發現,F(n)的值都介於 0~9 之間
因此可以把F(n)的數列看成這樣:
(0、1、2 ... 8、9)、F(10)、(1 、2 ... 8、9)、F(20) ... (1、2 ... F(n))
然後根據函示 F(n) 的定義如果 n 可以被 10 整除,則 F(n) = F(n/10)
再把上面的式子化簡成下面這樣:
(0、1、2 ... 8、9)、F(1)、(1 、2 ... 8、9)、F(2) ... (1、2 ... F(n))
整理後這樣題目就好解多了!
程式碼解說
這題可以分成三個函式
*回傳的值有可能超過 int 能表示的上限因此用 long long int
*回傳的值有可能超過 int 能表示的上限因此用 long long int
- f => 計算 F(n) 的值。
- sum => 計算等差級數的總和。
- f_sum => 計算 S(p, q) 的值,也就是算 F(p) 累加到 F(q) 的總和。
// C++ int f(int n); long long int sum(int from, int to); long long int f_sum(int p, int q);
先根據定義寫出一個 F(n) 的函式
// C++ int f(int n) { if(n%10) return n%10; else if(!n) return 0; else return n/10; }
再來寫一個計算等差級數總和的函式
// C++ long long int sum(int from, int to) { int count = to - from + 1; return (from+to) * count / 2; }
接下來寫一個函式計算 S(p, q)
先把結尾是 (1~9) 的數字做一個間隔來切割,如下:
0、(1、2 ... 9)、10、(11、12 ... 19)、20、(21、22 ... 29) ...
如果 p 跟 q 在同一個區間的話則直接累加
// C++ if((p/10) == (q/10)) { ans += sum(f(p), f(q)); }
若 p 、q 在不同區間的話,先把不能湊成一個完整區間的數字累加起來。
ex:
(8、9)、10、(11、12 ... 18 、 19)、20、(21、22、23)
=> 10、(11、12 ... 18 、 19)、20 為一個完整的區間
=> (8、9) 、 (21、22、23) 不是完整的區間
讓 F(p) 一直累加到 9,並更新 p 的位置到還沒運算的地方
// C++ if(p%10) { ans += sum(f(p), 9); p += (10-p%10); }
作法跟上面類似,從 1 累加到 F(q),並更新 q 的位置到還沒運算的地方
// C++ if(q%10){ ans += sum(1, f(q)); q -= q%10; }
在來用 p、q 來計算之間有幾個間隔,在乘上每個間隔中的總和
// C++ ans += ((q/10 - p/10) * sum(1, 9));
最後再加上 10 的倍數序列 的總和就可以得出答案了
*若 n 是10的倍數 根據 F(n) 定義也就等同於 F(n/10)
*若 n 是10的倍數 根據 F(n) 定義也就等同於 F(n/10)
// C++ ans += f_sum(p/10, q/10);
0 意見 :
張貼留言