题目:找出区间[A, B]内所有数字的奇数字位出现次数为偶数,偶数字位出现次数为计数的数的个数。
分析:这道题的状态同样不好取,因为要求每一个奇数的个数都要为偶数,每一个偶数的位数都要为奇数,又因为只有10个数(0~9),又因为没个数只有3种状态,分别是没有(0),奇数个(1),偶数个(2),这样我们就利用3进制进行压缩就可以了,3的10次方不超过60000,因此直接开60000即可,这样dp[i][j]的i表示当前处理到了第i为,j表示当前(0~9)对应的状态
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 25;
typedef long long LL;
LL dp[maxn][60000],bit[maxn];
int judge(int state){ //计算是否满足题意,奇数为偶,偶数为奇
for(int i = 0; i <= 9; ++i, state/=3) {
if((i&1)==1&&state%3==1) {
return 0;
}
if((i&1)==0&&state%3==2) {
return 0;
}
}
return 1;
}
int change(int state,int i){
int temp = state;
int j = i;
while(j--){///取到当前位
temp /= 3;
}
int x = temp%3;
if(x == 0)
state += (int)pow(3.0, i);
else if(x == 1)
state += (int)pow(3.0, i);
else
state -= (int)pow(3.0, i);
return state;
}
LL dfs(int pos,int state,int limit){
if(pos < 1) return judge(state);
LL &ans = dp[pos][state];
if(!limit && ans != -1) return ans;
LL ret = 0;
int len = limit?bit[pos]:9;
for(int i = 0; i <= len; i++)
ret += dfs(pos-1, state==0&&i==0?0:change(state, i), limit&&i==len);
if(!limit) ans = ret;
return ret;
}
LL solve(LL n){
int len = 0;
while(n){
bit[++len] = n%10;
n /= 10;
}
return dfs(len, 0, 1);
}
int main()
{
int T;
scanf("%d", &T);
LL A,B;
memset(dp, -1, sizeof(dp));
while(T--){
scanf("%lld%lld", &A, &B);
printf("%lld\n", solve(B)-solve(A-1));
}
return 0;
}