bzoj1026-windy數-數位DP-遞推寫法與遞迴寫法
(有任何問題歡迎留言或私聊 && 歡迎交流討論哦
題意:傳送門
原題目描述在最下面。
windy定義了一種windy數。不含前導零且相鄰兩個數字之差至少為2的正整數被稱為windy數。 windy想知道,在A和B之間,包括A和B,總共有多少個windy數?
思路:
遞推:
dp[i][j]
表示前 i 位第 i 個位置放上數字 j 的合法數字個數(從低位往高位的第 i 位)
dp[i][j] += dp[i-1][k] if(abs(j - k) >= 2)
對於數字num取出它的每一位後,考慮三種情況:(x是最高位數字)
一:首位填0:
ans += dp[i][j]
二:首位填[1, x - 1]:
ans += dp[pos][i]
i∈[1, x - 1]
三:首位填x:
if(abs(j - ar[i+1])>=2)
ans += dp[i][j]
i∈[1, pos - 1], j ∈[0, 9]
記得如果這個數字本身也符合wind數,記得加1.
遞迴:
拿普通數位DP的模板就行了。
記錄一下前導0和前一位數字dfs即可。
AC程式碼:
遞推:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
typedef long long LL;
const int N = 1e3+7;
const int INF = 0x3f3f3f3f;
LL n, m, ar[25];
LL dp[N][N];
LL ab(LL x){
return x<0?-x:x;
}
void init(){
for(int i = 0; i <= 9; ++i){
dp[1][i] = 1;
}
for(int i = 2; i <= 10; ++i){
for (int j = 0; j <= 9; ++j){
for(int k = 0; k <= 9 ;++k){
if(ab(j - k)>=2){
dp[i][j] += dp[i-1][k];
}
}
}
}
}
LL slove(LL x){
if(x <= 9)return x;
int pos = 0;
while(x){
ar[++pos] = x%10;
x /= 10;
}
LL sum = 0;
//最高位取0
for(int j = pos - 1; j >= 1; --j){
for(int i = 1; i <= 9; ++i){
sum += dp[j][i];
}
}
//最高位取1-ar[pos]-1
for(int i = 1; i < ar[pos]; ++i){
sum += dp[pos][i];
}
//最高位取ar[pos]
for(int i = pos-1; i >= 1; --i){
for(int j = 0; j < ar[i]; ++j){
if(ab(j-ar[i+1])>=2){
sum += dp[i][j];
}
}
if(ab(ar[i+1]-ar[i])<2)break;
if(i == 1)sum++;
}
return sum;
}
int main(int argc, char const *argv[]){
init();
while(~scanf("%lld%lld", &n, &m)){
printf("%lld\n", slove(m) - slove(n-1));
}
return 0;
}
遞迴:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cassert>
using namespace std;
typedef long long LL;
const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;
int n, m;
int ar[N], dp[20][10];
inline int ab(int x){
return x<0?-x:x;
}
int dfs(int pos, int pre, bool lead, bool limit){
if(pos == -1) return 1;
if(!limit&&!lead&&dp[pos][pre] != -1) return dp[pos][pre];
int up = limit? ar[pos]: 9, sum = 0;
for(int i = 0; i <= up; ++i){
if(pre==-1&&i==0){
sum += dfs(pos-1,pre,lead,limit&&i==ar[pos]);
}else if(ab(pre-i)>=2){
sum += dfs(pos-1,i,lead&&i==0,limit&&i==ar[pos]);
}
}
if(!limit&&!lead)dp[pos][pre] = sum;
return sum;
}
int solve(int x){
int pos = 0;
while(x){
ar[pos++] = x%10;
x /= 10;
}
return dfs(pos-1, -1, 1, 1);
}
int main(){
memset(dp, -1, sizeof(dp));
while(~scanf("%d%d", &n, &m)){
printf("%d\n", solve(m) - solve(n - 1));
}
return 0;
}
原題目描述:
相關推薦
bzoj1026-windy數-數位DP-遞推寫法與遞迴寫法
(有任何問題歡迎留言或私聊 && 歡迎交流討論哦 題意:傳送門 原題目描述在最下面。 windy定義了一種windy數。不含前導零且相鄰兩個數字之差至少為2的正整數被稱為windy數。 windy想知道,在A和B之間,包括A和B
bzoj1026 windy數 數位dp 記憶化搜尋
bzoj1026 windy數 題目大意:求[A,B]相鄰兩位差>=2的個數 1 <= A <= B <= 2000000000 題解: 在網上找了找題解都是用上一種方法
bzoj1026: [SCOI2009]windy數 數位dp
windy數 class tar 搜索 abs www main pos 之間 題目: http://www.lydsy.com/JudgeOnline/problem.php?id=1026 題意: Description windy定義了一種windy數。不含前導零且相
HYSBZ - 1026 windy數 [數位DP]
pos 絕對值 規模 處理 BE size name contain 數字 windy定義了一種windy數。不含前導零且相鄰兩個數字之差至少為2的正整數被稱為windy數。 windy想知道,在A和B之間,包括A和B,總共有多少個windy數? Input
BZOJ.1026.[SCOI2009]windy數(數位DP)
TP span memset sca string return bool include res 題目鏈接 數位DP。sb了。。 前導0是有影響的,影響第一位的選擇,所以要記。再記錄上限,然後在沒有限制時記憶化。 //820kb 4ms #include <cstd
bzoj 1026 [SCOI2009]windy數——數位dp水題
https zoj target ios tdi end () targe != 題目:https://www.lydsy.com/JudgeOnline/problem.php?id=1026 迷戀上用dfs寫數位dp了。 #include<iostream>
【BZOJ 3326】[Scoi2013]數數 數位dp+矩陣乘法優化
spa void pla color calc() class fin 左右 明顯 挺好的數位dp……先說一下我個人的做法:經過觀察,發現這題按照以往的思路從後往前遞增,不怎麽好推,然後我就大膽猜想,從前往後推,發現很好推啊,維護四個變量,從開始
【CCF】有趣的數 數位dp
clu 有趣 sizeof clas tdi return CA queue In 【思路】 dp[i][j]表示前i個數為第j種狀態,考慮6種狀態 0: 出現且僅出現 2 1: 出現且僅出現 2 0 2: 出現且僅出現 2 3 3: 出現且僅出現 2 0 1 4: 出現且
LUOGU P3413 SAC#1 - 萌數(數位dp)
int length 一位數 位數 iostream amp str mat ostream 傳送門 解題思路 首先這道題如果有兩個以上長度的回文串,那麽就一定有三個或兩個的回文串,所以只需要記錄一下上一位和上上位填的數字就行了。數位\(dp\),用記憶化搜索來實現。設
BZOJ 3326 [SCOI2013]數數 (數位DP)
狀態 數位 求和 連續 b+ getch 但是 數量 space 題目: Fish 是一條生活在海裏的魚,有一天他很無聊,就開始數數玩。他數數玩的具體規則是: 確定數數的進制$B$ 確定一個數數的區間$[L, R]$ 對於$[L, R] $間
hdu 6156 迴文數 數位dp
題意:k進位制下的迴文個數。。其實就是普通的。。稍加修改 思路:老題,直接列舉L進位制--R進位制 程式碼: #include<bits/stdc++.h> using namespace std; #define MEM(a,b) memset(a,b,sizeof
hiho 題目1 : 非法二進位制數(數位dp)
描述 如果一個二進位制數包含連續的兩個1,我們就稱這個二進位制數是非法的。 小Hi想知道在所有 n 位二進位制數(一共有2n個)中,非法二進位制數有多少個。 例如對於 n = 3,有 011, 110, 111 三個非法二進位制數。 由於結果可能很大,你只需要輸出
數位dp對於狀態描述與發現的一些感悟
code scanf ble 數字 統計 .cn detail 今天 size 今天刷的數位dp 第一題看了題解以後知道了數位dp的基本板子,寫數位dp的方式(運用記憶化遞歸的方法)已經基本固定。 那麽接下來的難點主要還是對於題目描述的問題,如何抽象成dp中的狀態。就今天刷
遞推演算法和遞迴演算法
#include<iostream> using namespace std; int fab(int n) { if (n == 1 || n == 2) { return 1; } else { return fab(n - 2) + fab(
Bailian1664 Placing apples【遞推+記憶化遞迴】
1664:Placing apples 總時間限制: 1000ms 記憶體限制: 65536kB 描述 We are going to place M same apples into N same plates. There could be some empty plates. How many meth
斐波那契數列陣列遞推,普通遞迴,記憶化搜尋,矩陣快速冪,和公式法
直接數列遞推推的時候是O(n)的複雜度,查詢的時候是O(1),但是當n很大的時候,陣列空間可能有點力不從心 #include <iostream> #include <cstdio> using namespace std; int fb[4
數位DP 《 菜鳥與大牛在於一念之間》
hdu3555 #include<iostream> #include<algorithm> #include<cstdio> #include<string.h> using namespace std; __int64
遞推演算法與二分演算法
遞推演算法與二分演算法 遞推演算法: (一)斐波那契數列 以下數列0 1 1 2 3 5 8 13 21 …被稱為斐波納契數列。 這個數列從第3項開始,每一項都等於前兩項之和。 輸入一個整數N,請你輸出這個序列的前N項。 輸入格式 一個整數N。 輸出格式 在一行中輸出斐波那契數列的前N項,數字之
2018.09.29【BZOJ1026】【洛谷P2657】【SCOI2009】windy數(數位DP)
洛谷傳送門 解析: 由於資料範圍很小(相對於大部分數位DPDPDP題來說)。 我們只記錄當前位,當前位數字,是否是前導0,是否達到上界。 簡單DP記憶化搜尋一下就好了。 程式碼: #include
[暑假集訓--數位dp]UESTC250 windy數
make 技術分享 -s -- esp etc play bsp map windy定義了一種windy數。 不含前導零且相鄰兩個數字之差至少為22 的正整數被稱為windy數。 windy想知道,在AA 和BB 之間,包括AA 和BB ,總共有多少個windy數? Inp