一道经典数位DP
断断续续想了一周,终于看懂了
题目如下
题意很简单,给出a,b,求出a-b间的windy数
windy数指相邻两位之差大于或等于2的数
最暴力的做法,把a-b扫一遍
但明显会超时(10^9)
优化做法是使用数位DP
按照这种分类标准
状态设计如下
d[i][j]--最高位为j的i位数中windy数个数
d[i][j]->d[i+1][k],前提是jk之差大于或等于2
#include<bits/stdc++.h>
using namespace std;
long long l,r,d[15][11],res,num[15],xx,cnt;
void pre()
{
for(int i=0;i<=9;i++)
d[1][i]=1;
for(int i=2;i<=13;i++)
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++)
if(abs(j-k)>=2)
d[i][j]+=d[i-1][k];
return ;
}
long long dp(long long x)
{
res=0;
xx=x;
cnt=0;
while(xx!=0)
{
cnt++;
num[cnt]=xx%10;
xx/=10;
}
//step 1--小于cnt位
for(int i=1;i<=cnt-1;i++)
for(int j=1;j<=9;j++)
res+=d[i][j];
//step 2--等于cnt位,最高位为从1开始
for(int i=1;i<=num[cnt]-1;i++)
res+=d[cnt][i];
//step 3--低于cnt位,次高位及其低位为从0开始
for(int i=cnt-1;i>=1;i--)
{
for(int j=0;j<=num[i]-1;j++)
if(abs(j-num[i+1])>=2)
res+=d[i][j];
if(abs(num[i+1]-num[i])<2)//x在i+1和i位本就不合法
break;
}
return res;
}
int main()
{
pre();
scanf("%lld %lld",&l,&r);
if(l>r)//题目没说l,r大小关系
swap(l,r);
printf("%lld",dp(r+1)-dp(l));//dp(x)求出的是[1,x-1]间的(写错了)
return 0;
}