windy数的定义:
较长的windy数与较短的windy数之间的关系:
于是可设计状态:
状态转移方程:
计算结果:
写%I64d\n居然是PE啊= =
相邻两数位之间的差不小于2.
这个定义表明windy数的一部分一也是windy数.
较长的windy数与较短的windy数之间的关系:
当较短的数是windy数时,只要考虑加的那一位和最高位之间的差是否大于1.
最高位.
于是可设计状态:
dp[i][j]----有i位的数中,最高位为j的windy数的个数.
状态转移方程:
dp[i][j] += dp[i-1][k]( k = 0..9 && |j-k| < 2)预处理是 考虑首位为0的情况的,因为用它的时候它常常不是首位.计算的时候避免即可.
计算结果:
这个时候必须分开算.不足len位的情况要累加.因为此时不考虑先导0.
如果像Bomb那道题一样直接并入最高位的计算的话就考虑了先导0.
len位数的计算就仿照Bomb了.
仍然注意:
从高位到低位,讨论的数逐渐增大逼近上界,当某一位固定为子串最高位时(即与原数的该位相同时)
若恰好违背windy数,那么计算终止.因为此位已经是最大的了,而以此位为最高位的所有数都非法,
也就是说此后直到上界,都不可再增加,因此计数终止.
//808 kb 0 ms
#include <cstdio>
using namespace std;
const int MAXN = 12;
typedef long long ll;
ll dp[MAXN][10];
int bit[MAXN];
int len;
int abs(int x)
{
return (x + (x>>31))^(x>>31);
}
void InitDP()
{
for(int i=0;i<10;i++) dp[1][i] = 1;
for(int i=2;i<MAXN;i++)
for(int j=0;j<10;j++)
for(int k=0;k<10;k++)
if(abs(j-k)>1) dp[i][j] += dp[i-1][k];
}
void pre(int x, int &len)
{
int i;
for(i=1; x; i++)
{
bit[i] = x % 10;
x /= 10;
}
bit[i] = 0;
len = i-1;
}
ll cal(int x)
{
ll ret = 0;
for(int i=1;i<len;i++)
for(int j=1;j<10;j++)
ret += dp[i][j];
for(int i=1;i<bit[len];i++)
ret += dp[len][i];
for(int i=len-1; i; i--){
for(int j=0;j<bit[i];j++)
if(abs(bit[i+1]-j)>1) ret += dp[i][j];
if(abs(bit[i+1]-bit[i])<2) break;
}
return ret;
}
int main()
{
int a,b;
InitDP();
while(scanf("%d %d",&a,&b)==2)
{
ll ansa,ansb;
pre(a,len);
ansa = cal(a);
pre(++b,len);
ansb = cal(b);
printf("%lld\n",ansb-ansa);
}
}
写%I64d\n居然是PE啊= =