Project Euler 776
Project Euler 776
题目
Digit Sum Division
For a positive integer $n$, $d(n)$ is defined to be the sum of the digits of $n$. For example, $d(12345)=15$.
Let $\displaystyle F(N)=\sum_{n=1}^N \frac n{d(n)}$.
You are given $F(10)=19$, $F(123)\approx 1.187764610390e3$ and $F(12345)\approx 4.855801996238e6$.
Find $F(1234567890123456789)$. Write your answer in scientific notation rounded to twelve significant digits after the decimal point. Use a lowercase e to separate the mantissa and the exponent.
解决方案
不难发现,可以将$F$进行改写:
改写后,相当于将$1\sim N$以内的所有数按照数位和分类好,再将它们求和即可,考虑使用动态规划的方法进行。
令$N=1234567890123456789$。考虑将$N$写成一个长度为$l$的十进制字符串$N=d_1d_2d_3\dots d_l$。
由于$N$很小,因此总数位和不会很大。
令中间状态$c_1(i,j)(1\le i\le l,0\le j\le 9i)$分别表示如下含义:有多少个$i$位有前导0的数,其数位和为$j$,并等于由字符串$d_1d_2\dots d_i$表示的数。令状态$s_1(i,j)$表示$c_1(i,j)$中的所有数之和。
不难发现,如果$j=\sum_{k=1}^i d_k$,那么$c_1(i,j)=1$,$s_1(i,j)$的值则为$d_1d_2\dots d_i$这一个字符串的十进制数;否则$c_1(i,j)=s_1(i,j)=0$。
状态$c_1$和$s_1$的意义在于规定了答案严格在界限上的情况。而接下来定义的状态$c_0,s_0$则是严格不在界限上的情况。
令状态$c_0(i,j)$表示有多少个$i$位有前导0的数,其数位和为$j$,并严格小于由字符串$d_1d_2\dots d_i$表示的数。令状态$s_0(i,j)$表示$c_0(i,j)$中的所有数之和。
那么可以先写出$c_0$的状态转移方程:
方程最后一行的第一个求和项说明,如果之前的状态已经是严格小于$d1d_2\dots d{i-1}$的数,那么接下来无论在后面拼接哪一个数位,都是严格小于的;对于第二个求和项而言,如果之前取的值都是严格等于的,那么接下来最多只能取到$d_{i-1}$。
那么基于$c_0$的思想,同样不难写出$s_0$的状态转移方程:
计算完成后,那么就可以计算$F(N)$:
代码
1 | N = 1234567890123456789 |