# FZU 2109 Mountain Number 數位DP

``````One integer number x is called "Mountain Number" if:
(1) x>0 and x is an integer;
(2) Assume x=a[0]a[1]...a[len-2]a[len-1](0≤a[i]≤9, a[0] is positive). Any a[2i 1] is larger or equal to a[2i] and a[2i 2](if exists).
For example, 111, 132, 893, 7 are "Mountain Number" while 123, 10, 76889 are not "Mountain Number".
Now you are given L and R, how many "Mountain Number" can be found between L and R (inclusive) ?
``````

Input

``````The first line of the input contains an integer T (T≤100), indicating the number of test cases.
Then T cases, for any case, only two integers L and R (1≤L≤R≤1,000,000,000).
``````

Output
For each test case, output the number of “Mountain Number” between L and R in a single line.
Sample Input

``````3
1 10
1 100
1 1000
``````

Sample Output

``````9
54
384
``````
``````#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int T,l,r,dp[15][15][2],b[15];
//v當前位置,pre前一個數字,odd_1=奇數_0=偶數,flag_1達到上限;
int seek(int v,int pre,int odd,int flag)
{
if(v==-1)return 1;
if(dp[v][pre][odd]!=-1&&!flag)return dp[v][pre][odd];//dp exists on flag;
//dp若有值一定>0,故若在main外定義可免去初始化，就讓其為0；
int lim=flag?b[v]:9;
int res=0;
for(int i=0;i<=lim;i  )
{
if(odd&&i<=pre)res =seek(v-1,i,!odd,flag&&i==b[v]);
else if(!odd&&i>=pre)res =seek(v-1,i,!odd,flag&&i==b[v]);
}
if(!flag)dp[v][pre][odd]=res;//if(flag) informal can't be tagged;
return res;
}
int solve(int x)
{
if(x==0)return 1;
int ans=0;
while(x)
{
b[ans  ]=x%10;
x/=10;
}
return seek(ans-1,9,1,1);
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&l,&r);
memset(dp,-1,sizeof(dp));
//由於解有solve(r)-solve(l-1)得到，整個資料中dp值是一樣的，故其實不必memset;
printf("%d\n",solve(r)-solve(l-1));//solve(r)-solve(l-1);
}
return 0;
}``````

``````#include<iostream>
#include<cstdio>
using namespace std;
int T,L,R,bit[15],dp[15][15][2];
//zero=1則有前導0； eg.  0~278中的(0)20；
int seek(int v,int pre,int odd,int zero,int flag)
{
if(v<0)return 1;
if(!flag&&dp[v][pre][odd])return dp[v][pre][odd];
int lim=flag?bit[v]:9;
int res=0;
/*本來以為下面對前導0的判定可簡化，但是沒成功*/
for(int i=0;i<=lim;i  )
{
if(zero==1&&i==0)res =seek(v-1,9,odd/*若i為0，一直是奇數位*/,zero,0);
else if(odd&&i<=fig)res =seek(v-1,i,!odd,0,flag&&i==bit[v]);//
else if(!odd&&i>=fig)res =seek(v-1,i,!odd,0,flag&&i==bit[v]);//
}
if(!flag)dp[v][pre][odd]=res;
return res;
}
int solve(int x)
{
int i=0;
while(x)
{
bit[i  ]=x%10;
x/=10;
}
return seek(i-1,9,1,1,1);
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&L,&R);
printf("%d\n",solve(R)-solve(L-1));
}
return 0;
} ``````

``````if(zero==1&&i==0)res =seek(v-1,9,odd/*若i為0，一直是奇數位*/,zero&&!i,flag&&i==bit[v]);
else if(odd&&i<=fig)res =seek(v-1,i,!odd,zero&&!i,flag&&i==bit[v]);//
else if(!odd&&i>=fig)res =seek(v-1,i,!odd,zero&&!i,flag&&i==bit[v]);//``````