HDU - 5898——odd-even number (数位DP)
- Time limit
1000 ms
- Memory limit
65536 kB
For a number,if the length of continuous odd digits is even and the length of continuous even digits is odd,we call it odd-even number.Now we want to know the amount of odd-even number between L,R(1<=L<=R<= 9*10^18).
Input
First line a t,then t cases.every line contains two integers L and R.
Output
Print the output for each case on one line in the format as shown below.
Sample Input
2 1 100 110 220
Sample Output
Case #1: 29 Case #2: 36
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
long long dp[25][2][2];
long long board[25];//存数的每一位的值
long long DFS(ll pos,ll pre,ll num,bool limit,bool lead){
//pos表示位,pre表示前一个位的奇偶性1为奇0为偶,num表示前面奇偶性的长度的奇偶性,limit判断上限,lead判断前导零。
if(pos == -1)return (pre && !num) || (!pre && num);
if(!limit && !lead && dp[pos][pre][num]!=-1)return dp[pos][pre][num];
ll up = limit?board[pos]:9;
ll ans = 0;
for(int _=0 ; _<=up ; _++){
if(lead && _==0)ans += DFS(pos-1,1,0,limit && _==up,true);
else if((_&1) && pre)ans += DFS(pos-1,pre,num^1,limit && _==up,false);
else if((_&1) && !pre && num)ans += DFS(pos-1,1,1,limit && _==up,false);
//这里当这一位的奇偶性与前一位不同时判断之前的位是否满足(!pre && num),因为不满足的就已经错了,没必要继续了。
else if(!(_&1) && pre && !num)ans += DFS(pos-1,0,1,limit && _==up,false);//同上
else if(!(_&1) && !pre)ans += DFS(pos-1,pre,num^1,limit && _==up,false);
}
if(!limit && !lead)dp[pos][pre][num] = ans;
return ans;
}
ll Solve(ll t){
ll pos = 0;
while(t){
board[pos++] = t%10;
t /= 10;
}
return DFS(pos-1,1,0,true,true);//这里传入pre=1,num=0是因为0个奇数也满足偶数个奇数,方便后面的状态转移。
}
int main(){
int T;
scanf("%d",&T);
ll A,B;
memset(dp,-1,sizeof(dp));
/*这里放在多组数据外面。这一点是一个数位特点,使用的条件是:约束条件是每个数自身的属性,而与输入无关。
即不管你输入的区间是多少你都无法改变这个数不满足约束这个事实,这就是数自身的属性。*/
for(int _=1 ; _<=T ; _++){
scanf("%lld %lld",&A,&B);
printf("Case #%d: %lld\n",_,Solve(B)-Solve(A-1));
}
return 0;
}