數字\(dp\)歸為計數\(dp\),通常需要統計乙個區間\([l,r]\)內滿足某些限制條件的個數
數字dp其實很久前就知道了,也做過幾道和其他演算法混在一起的題目,其實通過手玩是能做的
但畢竟是種演算法,還是系統學下比較好(節省手玩時間)
p2602 [zjoi2010]數字計數
求\([l,r]\)間,\(0\)到\(9\)在數字上出現的次數設陣列\(dp_i\)為滿\(i\)位每個數字出現的次數,也是說四位我們都算進去而忽略前導0的存在
而實際中顯然像0012這樣的數字我們是不會統計那兩個0的
(滿位情況下每個數字出現次數相同故我們可以公用空間)
則\(dp_i=dp_+10^\),理解??
比如從一位到兩位:
\(1.\)
\(0\)
$9$在第一位各出現一次,到兩位時它們前面補上$0$
\(9\)(第一位為0:00,10......90)故在\(dp_\)基礎上乘\(10\)
\(2.\)不僅要算原有位出現的次數,新加的該位也要算(第二位為1:10,11......19),數滿\(i-1\)位,故加上\(10^\)
當然你也可以手玩一遍驗證一下
#includeusing namespace std;
typedef long long ll;
ll dp[20],tmp[20],a[20];
int main()
for(ll i=0;i<=9999;++i)
for(ll j=1,bit=i;j<=4;++j)
++a[bit%10],
bit/=10;
printf("%lld",dp[4]);printf("\n");
for(ll i=0;i<=9;++i)
printf("%lld ",a[i]);printf("\n");
return 0;
}
現在來考慮前導\(0\),第\(i\)位為前導\(0\)時,實際上我們多算了填滿\(i-1\)位的次數,減去就好
my complete code(**有少量注釋,應該容易看懂)
#include#include#include#include#includeusing namespace std;
typedef long long ll;
inline ll read()
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}ll l,r;
ll a[20],cover[20],dp[20],countl[20],countr[20];
inline void solve(ll num,ll *a)
for(ll i=len;i>=1;--i)\)表示前\(i\)位,第\(i\)位為\(j\)的方案數\((\)稍微做過點動規的人這個都不成問題吧\()\)
考慮\(solve(x)\)為求\(x\)以內的答案
分三部分做\((\)設\(len\)為數字,每一位為\(a_i)\)
但我們發現其實是在計算\(x-1\)以內的答案\((\)第三部分使得最低位統計不到上界\()\)
#includeusing namespace std;
typedef long long ll;
ll l,r;
ll dp[15][10],a[15];
inline void calc()
inline ll solve(ll x)
for(ll i=1;i用記憶化搜尋來做,拋開迴圈後轉移狀態能更加隨意,大部分數字動規的題都可隨意切
拿上題舉例,我們用\(dfs(now,num,top)\)表示遍歷到第\(now\)位,上一位為\(num\),是否頂著上界
每層確定這一位選啥,判斷是否和上一位衝突,全部確定完了方案數\(+1\)
#includetypedef long long ll;
ll l,r;
ll f[11][10],a[11],dp[11][10];
inline void calc()
ll dfs(ll now,ll num,ll top)
inline ll solve(ll num)
ll ret(0);
for(ll i=1;i<=a[tot];++i) ret+=dfs(tot-1,i,i==a[tot]);
for(ll i=tot-1;i>=1;--i)
for(ll j=1;j<=9;++j)
ret+=dp[i][j];
return ret;
}int main()
搜尋的方法相比純迴圈計算,由於上道題限制較少難度簡單,故顯得有點雞肋
[cqoi2016]手機號碼
11位的手機號,在\([l,r]\)求出滿足兩個條件的方案數:至少有三位連續的數字相同,不能同時出現\(4\)和\(8\),\(dfs(now,p,pp,\_4,\_8,top,hw)\)
分別表示到第幾位了,前一位數字,前兩位數字,是否出現過\(4/8\),是否頂著上界,是否出現過了三連
用冗長的七重迴圈直接番了五倍的**量
#includeusing namespace std;
typedef long long ll;
ll l,r;
ll f[12][10][10][2][2][2],a[20];
ll dfs(ll now,ll p,ll pp,ll _4,ll _8,ll top,ll hw)
inline ll solve(ll x)
if(tot!=11) return 0;
ll ret(0);
for(ll i=1;i<=a[tot];++i)
ret+=dfs(tot-1,i,0,(i==4),(i==8),i==a[tot],0);
return ret;
}int main()
inline ll solve(ll x)
dfs(....);
return ret;
}
新手都能看懂的Dubbo!
1.dubbo架構 上述節點簡單說明 呼叫關係說明 1.服務容器負責啟動,載入,執行服務提供者。2.服務提供者在啟動時,向註冊中心註冊自己提供的服務。3.服務消費者在啟動時,向註冊中心訂閱自己所需的服務。4.註冊中心返回服務提供者位址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者...
小白都能看懂的block
首先說明一下,我自己也是乙個小白 這是我對block的一點認識或總結,有不對的地方,希望大家指出來 block就是乙個 塊,用來執行一小段程式的,通常我們定義乙個block 可以用它的基本模型,返回值型別 變數的名字 引數型別 例如 int myblock int 這就是定義了乙個block 這個變...
小白都能看懂的softmax詳解
softmax把一些輸入對映為0 1之間的實數,並且歸一化保證和為1,因此多分類的概率之和也剛好為1 或參考 小白都能看懂的softmax詳解 在機器學習尤其是深度學習中,softmax是個非常常用而且比較重要的函式,尤其在多分類的場景中使用廣泛。他把一些輸入對映為0 1之間的實數,並且歸一化保證和...