题意:
题意有点绕,odd-even数就是一个数 比方11222 就是,因为连续奇数的长度为2 而连续偶数的长度为3,但是11222333不行,因为3个3不满足连续奇数为偶数长度的条件。
dp[len][pre][need] 表示第len位 时,前一位的奇偶性,和前一位需不需要加多一个同奇偶性数使之合法。
转移的时候,根据题目条件转移即可。
由于不考虑前导零,那么对于 那些位数小于max_len的数,也即R为1e6,但数为1234时,这种不足六位的,前面的0不需要考虑,我们多个一个变量,来看是否整个数都为0,这种状态转移特判一下即可
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=5005+500;
ll dp[19][2][2];//第len位,pre位的奇偶,是否需要加一味
int aa[19];
// pos = 当前处理的位置(一般从高位到低位)
// pre = 上一个位的数字(更高的那一位)
// status = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回,
// 给计数器+1。
// limit = 是否受限,也即当前处理这位能否随便取值。如567,当前处理6这位,
// 如果前面取的是4,则当前这位可以取0-9。如果前面取的5,那么当前
// 这位就不能随便取,不然会超出这个数的范围,所以如果前面取5的
// 话此时的limit=1,也就是说当前只可以取0-6。
//
// qiandaozero,判断前导零
// 用DP数组保存这2个状态是因为往后转移的时候会遇到很多重复的情况。
//可根据需要增加维数,例如pre
ll dfs(int pos,int pre,int need,bool flag,bool qiandaozero)
{
ll ans=0;
if (pos==0) //已结搜到尽头,返回"是否找到了答案"这个状态。
{
if (!need&&!qiandaozero) return 1;
return 0;
}
//DP里保存的是完整的,也即不受限的答案,所以如果满足的话,可以直接返回。
if (!flag &&dp[pos][pre][need]!=-1&&!qiandaozero) return dp[pos][pre][need];
int up;
if (flag) up=aa[pos];
else up=9;
//根据是否受限确定枚举的上界
for (int i=0; i<=up; i++)
{
int ff;
if (!flag) ff=0;
else
{
if (i==up) ff=1;
else ff=0;
}
if (qiandaozero)
{
if (!i)
ans +=dfs(pos-1,i%2,0,ff,1);
else
ans +=dfs(pos-1,i%2,(i%2)?1:0,ff,0);
}
else
if (i%2==pre)
ans +=dfs(pos-1,i%2,!need,ff,0);
else
{
if (!need)
ans +=dfs(pos-1,i%2,(i%2)?1:0,ff,0);
}
}
//DP里保存完整的、取到尽头的数据
if (!flag&&!qiandaozero)
dp[pos][pre][need]=ans;
return ans;
}
int main()
{
memset(dp,-1,sizeof dp);
int tt,cas=0;
scanf("%d",&tt);
int m;
int cnt=1;
while (tt--)
{
ll a,b;
scanf("%lld%lld",&a,&b);
int len=0;
while(b)
{
aa[++len]=b%10;
b/=10;
}
ll ans2=dfs(len,0,0,1,1);
len=0;
a--;
while(a)
{
aa[++len]=a%10;
a/=10;
}
ll ans=dfs(len,0,0,1,1);
printf("Case #%d: %lld\n",cnt++,ans2-ans);
}
}