[a,b]不包含49的數的個數

https://blog.csdn.net/weixin_43701790/article/details/98379811


將區間1 ~ 581按上限拆開,分成1 ~ 499(百位數字小於5)、500 ~ 579(百位爲5,十位數字小於8)、580(百位爲5,十位是8,個位小於1)和581分成四個部分,以次計算每一個區間求和即可。(注意,581實際在for循環中不會處理,要在for循環後面補一個判斷"49")

初始化

f 代表前面[0,i-1]位有沒有49,res計算49的個數

dp[i][0] 不含49且開頭不是9
dp[i][1] 不含49且開頭是9
dp[i][2] 含49

dp[0][0]=1
# dp[1][0]=9
# dp[1][1]=1

for i in range(1,65):
    # 8是因爲首位不能是4或者9
    dp[i][0]=int(dp[i-1][0])*9+int(dp[i-1][1])*8
    dp[i][1]=int(dp[i-1][1])+int(dp[i-1][0])
    dp[i][2]=int(dp[i-1][2])*10+int(dp[i-1][1])

dfs判斷

以第i位對應的s[i]=a爲例:

無論s[i],f的值如何如果第i位取[0,a-1],那麼不受限情況下,res+=dp[len-i][2]*a

如果第i位取a,那麼受限情況下,res+=dp[len-i][2],如果a>4,那麼還得加上右側頭部爲9的情況即 res+=dp[len-i][1](如果 a==9,而且前面的第i-1位是4,那麼f=true

剩下的部分默認前面的位都取到了上限(比如1234->1xyz,12xy),因爲第一位爲0的已經dp得到所有解了。所以後面只要解決分拆後的12xy即可。

# 暴力法用於驗證
def bloom(n):
    counts=0
    for i in range(int(n)+1):
        if "49" in str(i):
            counts+=1
    return counts
# 數值dp
def dfs(n,dp):
    # res記錄各個位49的個數
    res=0
    # 記錄之前的i位是否有49
    f=False
    for i in range(len(n)):
        res+=int(n[i])*dp[len(n)-1-i][2]
        if f:
            res+=(dp[len(n)-1-i][1]+dp[len(n)-1-i][0])*(int(n[i]))
            # 堅持不求各位上的上界最大值 1234->12xx不求,只求11xx,10xx
        elif n[i]>"4":
            # 58 -> 49 上界大於4當然可以有49
            res+=dp[len(n)-1-i][1]
        # elif n[i]=="4":
        # 堅持不求各位上的上界最大值
        #     if i+1<len(n) and n[i+1]=="9":
        #         res+=dp[len(n)-1-i][1]
        if n[i]=="9" and (i-1>=0 and n[i-1]=="4"):
            f=True
    if "49" in n:
        res+=1
    return res

# dp[i][0] 不含49且開頭不是9
# dp[i][1] 不含49且開頭是9
# dp[i][2] 含49
dp=[]
for i in range(65):
    dp.append([0,0,0])

dp[0][0]=1
# dp[1][0]=9
# dp[1][1]=1

for i in range(1,65):
    # 8是因爲首位不能是4或者9
    dp[i][0]=int(dp[i-1][0])*9+int(dp[i-1][1])*8
    dp[i][1]=int(dp[i-1][1])+int(dp[i-1][0])
    dp[i][2]=int(dp[i-1][2])*10+int(dp[i-1][1])

n="49419"

print(dfs(n,dp),bloom(n))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章