巨大的數(dp+矩陣加速)

cn是大帅哥886發表於2024-08-16
第3題 巨大的數 檢視測評資料資訊

小明定義了一種生成大數的函式f[n],他的含義是將1-n所有的正整數按照從小到大拼接起來,形成一個巨大的數,例如f[13]=12345678910111213,現在給定一個數n,輸出f[n]%m的值,其中n和m都是正整數

輸入格式

第一行兩個整數n,m

部分資料:1<=n<=1e6

全部資料:1<=n<=1e18,1<=m<=1e9

輸出格式

一個整數

輸入/輸出例子1

輸入:

13 13

輸出:

4

樣例解釋

先考慮樸素dp

f(i): 前i個數拼起來,%m是多少
由f(i-1)轉移

舉個例分析下

假設有一串數,以i-1結尾,且f[i-1]=x,可以這樣表示:

(1234567...i-1)%m=x
令y=(1234567...i-1)
在這一串數後面加i,相當於變成:

(y*10^k+i)%m
=(y%m * 10^k%m + i)%m

那麼轉移方程就出來了

k: i有多少位
f(i) = ((f(i-1) * 10^k) %m + i) %m

然後我們算出矩陣

已知量肯定是f(i-1),i,由於有個10^k,我們還要補個1才能計算


[f(i-1), i, 1] * [A] = [f(i), i+1, 1]

[A]:

[10^k, 0, 0]
[1, 1, 0]
[0, 1, 1]

答案不就是[f(i-1), i, 1]*[A]^(i-1)嗎

但是k會變化!

所以考慮分段處理,分19段

k的長度:對應的值
1 :0~9
2 :10~99
3 :100~999
4 :1000~9999
............
18 : 10^17~10^18-1
19 : 10^18

那麼我們分別求出k的長度以及其對應的值,再改變一下矩陣,不就可以套算答案的那個公式了嗎?

具體地,我們要對n進行分段,分成k段,每段長度是i

為了方便,我們k從1開始(也可以從0開始,但是改變矩陣的時改變它的那個值要+1)

k的長度列舉範圍應該是1~n的長度

那麼就要考慮如何算出k所對應的這個區間裡面的數有多少個了。例如k=3,對應的區間的數個數就是 999-100+1=900

我們可以算出k對應的下限值。例如k=2,它對應的下限值是10,也就是 10^(k-1)+1,上限值是99,也是可以確定的,也就是10^k-1,那不就可以算了嗎

但是有個細節,我們得分類討論

1.現在迴圈的時候,n遠遠大於k所對應的區間的最大值,也就是n>k對應的區間的上限值,我們就可以直接算。例如n=1002,k=3,那麼k對應的值的範圍是100~999,我們可以直接用k對應的區間的上限減去下限(999-100+1)

那麼一般情況:n>10^k,上限值-下限值,也就是 10^k-1-(10^(k-1)+1)+1

2.現在迴圈的時候,n就再k所對應的區間之間,也就是n<k對應的區間的上限值,不就把上限值給調整下嗎。

相關文章