题意
在l到r区间内求有多少个符合条件“当前数中所有连续的奇数长度是偶数 所有连续的偶数长度是奇数”的个数
分析
典型的数位dp问题
我们设置dp数组时可以根据 dp[pos][pre][len]设定
表示在pos长度下 前面是pre并且长度是len的个数共有多少
这个方法很巧妙
根据这个结构 我们dfs(pos,pre,len,zero,limit)这样设置递归参数
我们把所有可能符合条件的分支都去搜索一遍
当我们到pos==0的时候 判断一下 此时如果pre和len的奇偶性不同 那么就返回1 表示这个数字
符合条件
因为当我们递归的时候是把所有可能的尝试都去做了一遍 所以如果当下的数 可能产生正确结果
就根据我们设置的dfs结构递归下去 最终都依靠 pos==0的判断 和之前所做的备忘得到结果
和缩小时间复杂度
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int d[20];
ll dp[20][20][20];
ll dfs(int pos,int pre,int len,bool zero,bool lim){
if(pos==0)return (pre&1)!=(len&1);
if(!lim&&~dp[pos][pre][len])return dp[pos][pre][len];
ll ans=0;
int up = lim==0?9:d[pos];
for(int i=0;i<=up;i++){
if(zero){
if(i==0)ans+=dfs(pos-1,0,0,1,i==up&&lim);
else ans+=dfs(pos-1,i,len+1,0,i==up&&lim);
}
else{
if(i&1){
if(pre&1)ans+=dfs(pos-1,i,len+1,0,i==up&&lim);
else if(len&1)ans+=dfs(pos-1,i,1,0,i==up&&lim);
}
else{
if(!(pre&1))ans+=dfs(pos-1,i,len+1,0,i==up&&lim);
else if(!(len&1))ans+=dfs(pos-1,i,1,0,i==up&&lim);
}
}
}
if(!lim)dp[pos][pre][len]=ans;
return ans;
}
ll solve(ll x){
int j=0;
while(x){
d[++j] = x%10;
x/=10;
}
return dfs(j,0,0,1,1);
}
int main()
{
int t;
ll l,r;
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%lld%lld",&l,&r);
printf("Case #%d: ",i);
memset(dp,-1,sizeof(dp));
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}