BZOJ1026_windy数_KEY

时间:2023-03-09 18:43:11
BZOJ1026_windy数_KEY

题目传送门

数位DP,其实只要求1~A-1和1~B就可以了。两数相减即为答案。

考虑怎们求1~A。

设f[i][j]表示到第i位,为j的windy数总数。

由前一位差值大于1的方程转移。

但是统计答案要分类讨论。

首先设所求数的位数为len。

1~len-1首先加入答案。

第len位的数-1也可以直接统计入答案。

统计每一位时,枚举当前位为j(<a[i]),与上一位比较。

j=1时,ans++。

code:

/**************************************************************
Problem: 1026
User: yekehe
Language: C++
Result: Accepted
Time:40 ms
Memory:824 kb
****************************************************************/ #include <cstdio>
#include <algorithm>
using namespace std; long long A,B,f[][]; long long a[];
long long solve(long long x)
{
if(!x)return ;
long long len=,ans=;
while(x)a[++len]=x%,x/=;
for(int i=;i<len;i++)
for(int j=;j<;j++)
ans+=f[i][j];
for(int i=;i<a[len];i++)ans+=f[len][i];
for(int i=len-;i;i--){
for(int j=;j<a[i];j++)
if(abs(j-a[i+])>)ans+=f[i][j];
if(abs(a[i]-a[i+])<)break;
if(i==)ans++;
}
return ans;
} int main()
{
scanf("%lld%lld",&A,&B);
for(int i=;i<=;i++)f[][i]=;
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int k=;k<=;k++)
if(abs(j-k)>)f[i][j]+=f[i-][k];
printf("%lld",solve(B)-solve(A-));
return ;
}