Project Euler 706
Project Euler 706
题目
$3$-Like Numbers
For a positive integer $n$, define $f(n)$ to be the number of non-empty substrings of $n$ that are divisible by $3$. For example, the string “$2573$” has $10$ non-empty substrings, three of which represent numbers that are divisible by $3$, namely $57, 573$ and $3$. So $f(2573) = 3$.
If $f(n)$ is divisible by $3$ then we say that $n$ is $3$-like.
Define $F(d)$ to be how many $d$ digit numbers are $3$-like. For example, $F(2) = 30$ and $F(6) = 290898$.
Find $F(10^5)$. Give your answer modulo $1\,000\,000\,007$.
解决方案
一个非常直接的动态规划题。
令$N=10^5.$考虑到子串的个数,通常我们先将这个数$d=d_1d_2d_3\dots$看成一个字符串,然后令其前缀和数组为$s$,其中$s[0]=0,s[i]=s[i-1]+d_i$,那么一个数的子串和就可以通过数组$s$进行一次减法求得。
令$N=10^5$,假设已有状态$f(i,c_1,c_2,k,t)(1\le i\le N,0\le c_1,c_2,t<3)$为有多少个$i$位数满足以下条件:
- 令$c_0=(i+1-c_1-c_2)\%3$。这两个值其实也是状态之一,只不过可以被$i,c_1,c_2$表出。
- 目前数组$s$一共有$i+1$项,其中有$c_j$个项模$3$的值为$j(0\le j<3)$ ,注意$c_j$已经被$3$取模。
- 目前$s[i]$的值为$k$。
- 子串个数和$t$关于模$3$同余。
那么状态的转移只需要考虑在每个数后面添加一个数位$0\sim 9$,注意维护前缀和数组$s$新的一项。
本题转移过程考虑进行我为人人式。
不难知道初值$f(1,0,0,0,1)=f(1,1,0,1,0)=f(1,0,1,2,0)=3$,这$3$种情况分别对应一位数模$3$余$0$,模$3$余$1$,模$3$余$2$的情况。
以$k=0$为例,那么有三种方式转移:
$\begin{aligned}
& f(i,c_1,c_2,0,t)\cdot 4\rightarrow f(i+1,c_1,c_2,0,(t+c_0)\%3) \
& f(i,c_1,c_2,0,t)\cdot 3\rightarrow f(i+1,(c_1+1)\%3,c_2,1,(t+c_1)\%3) \
& f(i,c_1,c_2,0,t)\cdot 3\rightarrow f(i+1,c_1,(c_2+1)\%3,1,(t+c_2)\%3) \
\end{aligned}$
由于目前的前缀和$s[i]=0$,那么再添加数位$0,3,6,9$中的一个,那么$s[i+1]=0$,因此这时就多了$c_0$个符合题意的子串;如果添加数位$1,4,7$中的一个,那么$s[i+1]=1$,因此这时就多了$c_1$个符合题意的子串;如果添加一个数位$2,5,8$,那么$s[i+1]=2$,因此这时就多了$c_2$个符合题意的子串。
因此,最终答案为
本题也可以将整个状态转移过程写成一个$81\times81$大小的矩阵,通过矩阵快速幂以$O(\log N)$直接计算出结果。此处不再详述这个优化。
代码
1 |
|