BZOJ 1016 Windy 数 | 数位DP
题目:
http://www.lydsy.com/JudgeOnline/problem.php?id=1026
题解:
f[i][j][1/0]表示枚举到第i位,这位开头是j,当前的数大于(1)或小于(0)目标数的Windy数个数
瞎JB转移即可
#include<cstdio> #include<algorithm> #include<cstring> typedef long long ll; using namespace std; ll f[15][15][2],sum[15],n,m; ll dp(int x) { int a[15],n=0,ret=0; while (x>0) a[++n]=x%10,x/=10; if (n==0) a[++n]=0; memset(f,0,sizeof(f)); for (int i=0;i<=9;i++) if (i<=a[1]) f[1][i][0]=1; else f[1][i][1]=1; for (int i=2;i<=n;i++) for (int j=0;j<=9;j++) for (int k=0;k<=9;k++) if (abs(j-k)>=2) { if (j<a[i]) f[i][j][0]+=f[i-1][k][1]+f[i-1][k][0]; else if (j==a[i]) f[i][j][0]+=f[i-1][k][0],f[i][j][1]+=f[i-1][k][1]; else f[i][j][1]+=f[i-1][k][0]+f[i-1][k][1]; } for (int i=1;i<=9;i++) if (i<a[n]) ret+=f[n][i][0]+f[n][i][1]; else if (i==a[n]) ret+=f[n][i][0]; for (int i=n-1;i;i--) for (int j=1;j<=9;j++) ret+=f[i][j][0]+f[i][j][1]; return ret; } int main() { scanf("%lld%lld",&n,&m); printf("%lld",dp(m)-dp(n-1)); return 0; }