luoguP2657 [SCOI2009] windy 数 数位dp
基本上把数位dp那一套给忘了,今天重学一遍.
感觉采用递推的方式还是蛮方便的,然后要注意几个细节:
1. 通常算 f(x+1)=calc(1,x),这样更方便算一些.
2. 每种小于最大长度的所有结果都要累加.
3. 很多时候不要忘记 0 的贡献.
4. 要特判前缀合不合法.
code:
#include <bits/stdc++.h>
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
ll f[20][20];
int num[20],cnt;
void init()
{
for(int i=0;i<10;++i) f[1][i]=1;
for(int i=2;i<11;++i)
for(int j=0;j<10;++j)
for(int k=0;k<10;++k)
if(abs(k-j)>=2) f[i][j]+=f[i-1][k];
}
ll calc(ll x)
{
memset(num,0,sizeof(num)),cnt=0;
do
{
num[++cnt]=x%10;
x/=10;
}while(x);
ll ans=0;
for(int i=1;i<cnt;++i)
for(int j=1;j<10;++j) ans+=f[i][j];
for(int i=1;i<num[cnt];++i)
ans+=f[cnt][i];
for(int i=cnt-1;i>=1;--i)
{
if(i+2<=cnt&&abs(num[i+1]-num[i+2])<2) break;
for(int j=0;j<num[i];++j) if(abs(num[i+1]-j)>=2) ans+=f[i][j];
}
return ans;
}
int main()
{
// setIO("input");
init();
ll L,R;
scanf("%lld%lld",&L,&R);
printf("%lld\n",calc(R+1)-calc(L));
return 0;
}

浙公网安备 33010602011771号