windy数-数位dp 解题报告

时间:2021-01-26 20:51:04

数位DP 一个init() 预处理出f[i][j] 即 长度为i的数最高位为j合法的方案数

一个solve() 传入一个参数n,意为处理出一到n合法的数字个数。然后相减,对了相减的时候要处理一下边界情况:处理时L,R是否已经添加了。

上述两个对数位dp有普适性,其余细节在代码中给出说明。

Code:

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define R register int
const int N=13;
int f[N][N],num[N],l,r;

void init(){
for(R i=0;i<=9;i++)f[1][i]=1;
for(R i=2;i<=10;i++){
for(R j=0;j<=9;j++){
for(R k=0;k<=9;k++){
if(abs(j-k)>=2)f[i][j]+=f[i-1][k];
}
}
}
}

inline int solve(int n){
memset(num,0,sizeof(num));
int ans=0,len=0;
while(n){
num[++len]=(n%10);
n/=10;
}
for(R i=1;i<len;i++)for(R j=1;j<=9;j++)ans+=f[i][j];
for(R i=1;i<num[len];i++)ans+=f[len][i];
for(R i=len-1;i>=1;i--){
for(R j=0;j<=num[i]-1;j++){ //j可以等于0的原因是因为这一位一定不是最高位,与前导0不冲突 
if(abs(j-num[i+1])>=2)ans+=f[i][j];
}
if(abs(num[i+1]-num[i])<2)break;//此句话会省去无用的枚举,因为如果靠左一位都以无法满足,再做下去就不必要了
}
return ans;
}


int main(){
scanf("%d%d",&l,&r);
init();
printf("%d\n",solve(r+1)-solve(l));
}