小明定義了一種生成大數的函式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對應的區間的上限值,不就把上限值給調整下嗎。