【題目來源】
https://www.acwing.com/problem/content/3713/
【題目描述】
給定兩個整數 l,r(l≤r),請問 [l, r] 範圍內,滿足數字的任意相鄰兩位差值都恰好為 1,且數字至少有兩位的數有多少個。
【輸入格式】
第一行包含整數 T,表示共有 T 組測試數據。
每組數據佔一行,包含兩個整數 l 和 r。
【輸出格式】
每組數據輸出一行,一個結果。
【輸入樣例】
14 2023
【輸出樣例】
1
17
【數據範圍】
1≤T≤100,
0≤l≤r≤3×10^8
【算法分析】
● 從最高位到最低位枚舉,最高位有 1~9 共 9 種選擇(最高位不能為 0)。其後的每一位,因為要滿足“任意相鄰兩位差值都恰好為 1”的約束條件,所以,最高位之後的每一位的值,只有兩種選擇。鑑於題目給出的最大數為 3×10^8,故總的選擇數為 9×2^8=2304。
● 也就是説,從最高位到最低位枚舉求解,不會超時(TLE)。
● 下面代碼中,函數 dfs 的各個形參含義:u表示當前數的位數,x表示當前數的值,pre記錄上一位數的值。
【算法代碼:】
#include <bits/stdc++.h>
using namespace std;
int le,ri,cnt;
int T;
//u表示當前數的位數,x表示當前數的值,pre記錄上一位數的值
void dfs(int u,int x,int pre) {
if(x>ri) return;
if(u>1 && x>=le && x<=ri) cnt++;
if(u==0) {
for(int i=1; i<10; i++) dfs(u+1,x*10+i,i);
} else {
if(pre) dfs(u+1,x*10+pre-1,pre-1);
if(pre<9) dfs(u+1,x*10+pre+1,pre+1);
}
}
int main() {
cin>>T;
while(T--) {
cnt=0;
cin>>le>>ri;
dfs(0,0,-1);
cout<<cnt<<endl;
}
return 0;
}
/*
in:
4
1 10
10 10
1 100
0 300000000
out:
1
1
17
1992
*/
【算法代碼:數位DP】→
#include <bits/stdc++.h>
using namespace std;
const int N=12;
int f[N][10]; //f[i][j]表示長度為i最高位為j的滿足條件的數字個數
void init() {
for(int i=0; i<=9; i++) f[1][i]=1;
for(int i=2; i<N; i++) {
for(int j=0; j<=9; j++) {
if(j==0) f[i][j]=f[i-1][1];
else if(j==9) f[i][j]=f[i-1][8];
else f[i][j]=f[i-1][j-1]+f[i-1][j+1];
}
}
}
int dp(int n) {
if(n<=0) return 0; //vip
vector<int> v;
while(n) {
v.push_back(n%10);
n/=10;
}
int cnt=0,pre=-1;
for(int i=v.size()-1; v.size()>=2 && i>=0; i--) {
int x=v[i];
int start=(i==v.size()-1)?1:0;
for(int j=start; j<x; j++) {
if(pre==-1 || abs(pre-j)==1) {
cnt+=f[i+1][j];
}
}
if(abs(pre-x)==1 || pre==-1) pre=x;
else break;
if(i==0) cnt++;
}
for(int i=2; i<=v.size()-1; i++) {
for(int j=1; j<=9; j++) cnt+=f[i][j];
}
return cnt;
}
int main() {
init();
int T,le,ri;
cin>>T;
while(T--) {
cin>>le>>ri;
cout<<dp(ri)-dp(le-1)<<endl;
}
}
/*
in:
4
1 10
10 10
1 100
0 300000000
out:
1
1
17
1992
*/