HDOJ 3555 不會按位DP的做法

2021-05-27 15:53:06 字數 1596 閱讀 1521

今天做的一套去年whu出的多校聯合題...這道題糾結了好久才擠出來....去網上搜了下...大牛們似乎都是用的高階的按位dp...我等小菜就只能做屎的想賴推了....

首先將每個位的表打出來...例如sum[3][1]代表100以下的有多少個包含49的數...sum[5][5]代表50000以下有多少包含49的數..首先要看10^k的sum會是多少...也就是sum[k][1]都是多少...其中k從0到10^19 ( 比2^64大的最小位置)....

稍微推一下...譬如知道sum[3][1]=20..也就是1000以內的是20..那麼1000 ~ 2000也是20...2000~3000也是20...3000~4000也是20..以此類推..則有20*10個了..然後在4000到5000中還有49xx的沒有記入..49xx的一共就是10*10一百個..但是4949會重複計算一次..所以是10*10-1 ( 往大的推會發現這裡的 「 1 " 是sum[i-2][1])...

所以10的階乘的 sum[i][1]=sum[i-1][1]*10+10^(i-1)-sum[i-2][1]....

然後在1~4時...sum[i][j]=j*sum[i][1]...這個很好想...每一段和 0 ~ 10^i是一樣的...有j段就乘以j......

但在5~9時...思想要轉過來...因為在4***xx ~ 5***xx我們又有更多的包含"49"數沒有記入...要加上去.則:  sum[i][j]=j*sum[i][1]+10^i-sum[i-1][1];

做好了這個表後....下面的工作就輕鬆多了...但也要注意...

如果簡單的 5983 = sum[4][5]+sum[3][9]+sum[2][8]+sum[1][3] 大部分是會對...但交上去會wa..原因是沒有考慮本身這個數就含了 " 49" 這種情況..

就拿最淺顯的來說 ..49 = sum[2][4] + sum[1][9]...的出來就會是0...再來..493 = sum[3][4]+sum[2][9]+sum[1][3] 得出來也會少...稍微思考一下這種情況也不難處理

如果我掃到了乙個49..那麼就做完9的sum累加後break...ans+=後面的數+1....如49=sum[2][4]+sum[1][9]+(0+1)..493=sum[3][4]+sum[2][9]+(3+1);這樣就能保證萬無一失了...

這樣做比較費腦細胞...也很費時間...這道題比較正規的方法應該是按位dp...本菜剛才看了好幾個文章都沒來感覺...慢慢來吧..      

program:

#include#include#includeusing namespace std;

long long sum[20][12],_10jie[20];

int t,i,n,x;

char s[100];

void prework()

_10jie[1]=1;

for (i=2;i<=19;i++) _10jie[i]=_10jie[i-1]*10;

}long long getanswer()

}k++;

}if (f)

return ans;

}int main()

return 0;

}

hdoj 3555 數字dp,詳細注釋

數字dp可以解決類似這樣一道給你上下界,求裡面符合要求的數字,暴力肯定超時的.下面給出帶注釋的 include includetypedef long long ll using namespace std ll dp 20 2 ll dight 20 ll dfs ll len,bool if4,...

數字DP 按位DP

之前說過要做個專題,雖然隔了好長時間。但說話還是算數的,把之前做的ppt翻出來貼上,好吧,我就是懶。見識的還是少,歡迎討論啊 數字dp 在給定區間 a,b 內,找滿足要求的數。要求一般和數大小無關,而與數的組成有關 例如,遞增的,1234,2579 雙峰的,19280,26193 含49的,49,1...

專題 數字DP 按位DP

自 數字dp 在給定區間 a,b 內,找滿足要求的數。要求一般和數大小無關,而與數的組成有關 例如,遞增的,1234,2579 雙峰的,19280,26193 含49的,49,149,1492 整除13的,26,39 麻煩在於,規模大,位數 100 不能列舉。區間往往不是整百整千,邊界問題 注意 記...