測試地址:數數
題目大意: 給定
兩個
位內的
進制數,
,對區間
內的全部數
,累加
中全部子串表示的數字的和(如
,應該累加
到答案中,注意不該該包含前導零),求最終答案(用
進製表示)。
作法: 本題須要用到數位DP。
神題。雖然一眼能看出數位DP,但具體的轉移式子仍是想錯了好多回,此次終於寫對了。
首先咱們來看,對於一個
位的數
,在它末尾加一位數
,會對這個數的全部子串表示的數字和有什麼影響(如下簡寫成
)。令
表示數
全部後綴表示的數字和,那麼有:
根據這個爲基礎,咱們就能思考數位DP的轉移了。
根據套路,首先把問題轉化爲:用小於等於
的全部數的貢獻,減去小於等於
的全部數的貢獻,因而如今咱們考慮求小於等於某個數
時的貢獻。
從高位向低位枚舉,令
表示前
位中,不卡/卡上界的全部數的
的和,
表示前
位中,不卡/卡上界的全部數的
的和。先分析具體的轉移過程:
前
位的數不卡上界時,第
位能夠填
~
內全部的數,而且新的數都不卡上界;
前
位的數卡上界時,第
位能夠填
~
。當填
~
時,新的數不卡上界,當填
時新的數卡上界。
因而咱們先考慮
的轉移。首先,卡上界的狀況應該很好轉移了,實際上就是求上界的
值。主要是不卡上界的狀況比較複雜。
首先考慮不卡上界轉移到不卡上界的狀況。根據上面的轉移式子
,咱們這樣考慮:首先枚舉
從
到
,對於每個
,再枚舉可轉移的
,把貢獻累加起來。因而一個
對整個
的貢獻是:
,那麼對於全部
,對
的貢獻就是:
。其中
就是
,而
須要斟酌一下。這個和式是在求,對於全部可轉移的
(包括
),累加它們的位數
(把
的位數看作
)。觀察規律,咱們發現:
有
個,
有
個,
有
個,
有
個…
有
個,
有
個,
表示
的前
位組成的前綴。那麼前面的有規律的部分能夠遞推維護,而
顯然也能夠遞推維護,因此咱們就能夠每次
地進行這個轉移了。
接下來考慮卡上界轉移到不卡上界的狀況。這種狀況下,能轉移到不卡上界的狀況,
必須是
~
,並且由於這種狀況中可轉移的
只有一個,並且
就是
,所以就比上面的狀況簡單不少了,總貢獻應該爲
。
那麼
的轉移討論完了,接下來討論
的轉移。
就是求上界的
,而
也利用上面的思考方式,先考慮從不卡上界轉移的狀況,由於有
種轉移,因此
就產生了
次的貢獻。再考慮從卡上界轉移的狀況,由於有
種轉移,因此
就產生了
次的貢獻。再加上全部不卡上界數的後綴產生的貢獻,即
,就能夠計算出
了。
至此,通過漫長的討論,咱們獲得了一個
的數位DP,完美地解決了這一道題。
如下是本人代碼:php
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=20130427; int n; ll s[100010],B,sum[100010][2],suf[100010][2]; ll pw[100010],num[100010],sumnum[100010]={0}; ll solve() { sum[0][0]=sum[0][1]=suf[0][0]=suf[0][1]=num[0]=0; for(int i=1;i<=n;i++) { if (i>2) sumnum[i]=(sumnum[i-1]+(ll)(i-1)*(B-1ll)%mod*pw[i-3]%mod)%mod; num[i]=(num[i-1]*B%mod+s[i])%mod; ll tmp=0; if (i>1) tmp=(sumnum[i]+1ll+(num[i-1]-pw[i-2]+mod)%mod*(ll)i%mod)%mod; suf[i][1]=(suf[i-1][1]*B%mod+s[i]*(ll)i%mod)%mod; suf[i][0]=(suf[i-1][0]*B%mod*B%mod+B*(B-1ll)/2ll%mod*tmp%mod)%mod; suf[i][0]=(suf[i][0]+suf[i-1][1]*B%mod*s[i]%mod+s[i]*(s[i]-1ll)/2ll%mod*(ll)i%mod)%mod; sum[i][1]=(sum[i-1][1]+suf[i][1])%mod; sum[i][0]=(sum[i-1][0]*B%mod+suf[i][0])%mod; sum[i][0]=(sum[i][0]+sum[i-1][1]*s[i]%mod)%mod; } return (sum[n][0]+sum[n][1])%mod; } int main() { ll ans; scanf("%lld",&B); scanf("%d",&n); pw[0]=1; for(int i=1;i<=n;i++) { scanf("%lld",&s[i]); pw[i]=pw[i-1]*B%mod; } ans=(mod-solve()+sum[n][1])%mod; scanf("%d",&n); pw[0]=1; for(int i=1;i<=n;i++) { scanf("%lld",&s[i]); pw[i]=pw[i-1]*B%mod; } ans=(ans+solve())%mod; printf("%lld",ans); return 0; }