1. 程式人生 > >bzoj1026-windy數-數位DP-遞推寫法與遞迴寫法

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]

i∈[1, pos-1], j∈[1, 9]

二:首位填[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