啃了半天的数位dp(认真体会)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define YES cout<<"YES"<<endl;
#define NO  cout<<"NO"<<endl;
#define endl '\n'
#define io ios::sync_with_stdio(false)
#define tie cin.tie(0),cout.tie(0)
#define MOD 998244353
#define inf 0x3f3f3f3f3f
#define maxn 1000006
//因为有10个数字 这里我们取11位的dp
/* i-1解释:
在动态规划数组中的转移:dp[i][j] 表示位数为 i 且从右往左数第 i 位数字为 j 的 Windy 数的个数。dp[i][j] += dp[i - 1][k] 意味着将位数为 i - 1 且第 i - 1 位数字为 k 的 Windy 数的个数,累加到位数为 i 且第 i 位数字为 j 的 Windy 数的个数上。这是因为在构建位数为 i 的 Windy 数时,需要考虑在位数为 i - 1 的 Windy 数的基础上,在更高一位(即第 i 位)添加数字 j 的情况。例如,当计算三位数的 Windy 数时,要基于已经计算出的两位数的 Windy 数情况来进行。
在数字位数上的转移:从数字的实际意义角度,i - 1 代表当前位数 i 的前一位。比如 i 为 3 时表示三位数,i - 1 就是 2,表示两位数。在循环过程中,先确定第 i 位(从右往左)的数字 j,然后通过内层循环遍历第 i - 1 位可能的数字 k,检查 k 和 j 的差值是否满足 Windy 数的条件(abs(k - j) >= 2),如果满足,就将 dp[i - 1][k] 累加到 dp[i][j],相当于把满足条件的前一位数字为 k 的 i - 1 位 Windy 数的数量,转移到了当前第 i 位数字为 j 的情况上,以此来统计位数为 i 的 Windy 数中第 i 位为 j 的个数。
*/
int dp[11][11];
  void init(){
  	 //当位数为1,取得数字可以为0~9,算作一个windy数,从最后往最前面推的
  	 for(int i=0;i<=9;i++) dp[1][i]=1;
  	 for(int i=2;i<11;i++){//遍历位数,直到第10位
  	 	 for(int j=0;j<=9;j++){//对于第j位,我都可以选择0~9来补充,此时不考虑前导0,因为对于j=0后面会进行dp转移,对于当前位数字j,遍历下一位(即第i - 1位)可能的数字k(0到9)
  	 	 	for(int k=0;k<=9;k++){//表示j的后一位可以选择的数字     
  	 	 		if(abs(k-j)>=2) dp[i][j]+=dp[i-1][k];
  	 	 	}
  	 	 }
  	 }
  };
  int dps(int m){
  	int res=0;//初始答案
    int cnt=0;//数字位数
    vector<int>a(11);//提取每个位数
    while(m>0) a[++cnt]=m%10,m/=10;//a数组存储的每个位数,从最低位到最高位 符合条件
    int last=-1;
    //答案是cnt位的
    for(int i=cnt;i>=1;i--){//i提取的是第几位数,最高是因为方便后续break  _____不断更新每个位可能存在的答案
    	int now=a[i];//表示当前的数字
    	for(int j=(cnt==i);j<now;j++){
    		 if(abs(j-last)>=2) res+=dp[i][j];//遍历,因为小于now的数字可能存在windy数
    	}
    	if(abs(now-last)<2) break;//假如是12553,遍历到2的时候发现2-1=1,此时小于2,那么对于12000,121..,120..都不是windy数了
    	last=now;//假如是,那么更新last为上一位的数字
    	if(i==1) res++;//单独最后一位
    }
    for(int i=1;i<cnt;i++){
    	for(int j=1;j<=9;j++){
    		res+=dp[i][j];
    	}
    }
    return res;
  }
signed main(){
    io,tie;
    init();
    int n,m;cin>>n>>m;
    //进行转移
    cout<<dps(m)-dps(n-1);
    return 0;
}
posted @ 2025-02-26 20:20  Qacter  阅读(18)  评论(0)    收藏  举报