UOJ 140 被粉碎的數字 數字DP

2022-06-06 11:15:06 字數 1287 閱讀 2593

傳送門

題意簡述:令\(f(x)\)為\(x\)的各位數字之和,求:

\[\sum_^[f(x)=f(kx)]

\]其中\(r\le 10^\),\(k< 1000\)

遇到跟數字和相關的問題,自然想到數字\(dp\)

為了處理\(kx\)進製的問題,我們從低位到高位考慮並維護目前\(kx\)向前一位進了多少:

考慮\(dp\)狀態\(dp[i][j][h][lim]\),表示已經考慮到了從低到高第\(i\)位,前\(i\)位中\(f(x)\)與\(f(kx)\)的差為\(j\)(為避免負數問題,實際表示的是\(f(x)=f(kx)+j-200\)),目前\(kx\)向前\(1\)位進了\(h\),\(lim\)則是數字\(dp\)中經典的表示目前填的位置是否\(>r\),滿足以上所有條件的\(x\)的個數

數字之和最大不超過\(200\),因此\(j\)只用列舉到\(400\),因為\(k<1000\),所以進製不超過\(999\)。

轉移就是直接列舉當前第\(i+1\)位選擇的數\(x\),則有

\[dp[i+1][j+x-(kx+h)\%10][(kx+j)/10][nlim]+=dp[i][j][h][lim]

\]其中\(nlim\)滿足:對於\(r\)的第\(i+1\)位\(a[i+1]\),如果\(x>a[i+1]\),則\(nlim=1\),如果\(x,則\(nlim=0\),否則\(nlim=lim\)

那麼直接列舉轉移即可,初始狀態為\(dp[0][200][0][0]=1\)

注意有可能填到\(r\)的最高位時還有一些進製沒有處理,因此我們可以認為\(r\)多出了三位\(0\)來將進製處理完

而\(ans=\)

\[dp[len][200][0][0]-1

\]\(-1\)是為了除去\(0\),\(len\)就是\(r\)的位數\(+3\)

#includeusing namespace std;

typedef long long ll;

ll r,t,f[30][400][1010][2];

ll a[50],len;

int main()

len+=3;

f[0][200][0][0]=1;

for(int i=0;ia[i+1]) nlim=1;

if(xf[i+1][j+x-nx][nr][nlim]+=f[i][j][k][lim];}}

}} }

printf("%lld\n",f[len][200][0][0]-1);

return 0;

}

uoj140 UER 4 被粉碎的數字

題目 看起來就像是數字 rm dp 不妨從豎式乘法的角度來考慮這個問題 為了方便處理進製,我們得從低位向高位填數 設 dp i 0 1 j p t 表示填到了第 i 位,卡不卡上界,f x j f k times x p 不計算最高位 需要向最高位進 t 的 x 有多少個 這裡的卡上界比較奇怪,如果...

Jzoj4747 被粉碎的線段樹

額這個題麼 有乙個很關鍵的點 結點個數依然為2n 1 證明可以看sam的講稿 不難發現以下性質 區間定位個數 區間所覆蓋的節點個數 2 區間長度 所以問題變為,乙個區間覆蓋了多少個節點?我們可以求出所有的節點,然後這個問題就是乙個二維偏序計數問題了 具體用離線 按照r排序套上樹狀陣列即可 inclu...

Jzoj4747 被粉碎的線段樹

額這個題麼 有乙個很關鍵的點 結點個數依然為2n 1 證明可以看sam的講稿 不難發現以下性質 區間定位個數 區間所覆蓋的節點個數 2 區間長度 所以問題變為,乙個區間覆蓋了多少個節點?我們可以求出所有的節點,然後這個問題就是乙個二維偏序計數問題了 具體用離線 按照r排序套上樹狀陣列即可 inclu...