题目链接:https://vjudge.net/problem/SPOJ-BALNUM

题意:个数被称为是平衡的数当且仅当对于所有出现过的数位,偶数出现奇数次,奇数出现偶数次。

给定A,B,请统计出[A,B]内所有平衡的数的个数。

解法:

注意,这里的偶数是指出现过的数,并且不能计算前导零。

对于每一个数有三种状态:

0:这个数还木有出现过。

1:这个数出现过奇数次。

2:这个数出现过偶数次。

所以直接用一个三进制数表示状态,然后转移吧。

///SPOJ 10606

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int dp[20][60000];
int digit[20];
LL pos[11];
void init(){
    pos[0]=1;
    for(int i=1; i<=10; i++) pos[i]=pos[i-1]*3;
}
bool judge(int s){
    for(int i=9; i>=0; i--){
        if(i%2==0&&s/pos[i]==2) return false;
        if(i%2==1&&s/pos[i]==1) return false;
        s%=pos[i];
    }
    return 1;
}
LL dfs(int l, int s, bool zero, bool jud){
    if(l==0){
        if(judge(s)) return 1;
        else return 0;
    }
    if(!jud&&dp[l][s]!=-1) return dp[l][s];
    int up = jud?digit[l]:9;
    LL ans=0;
    for(int i=0; i<=up; i++){
        ans+=dfs(l-1,zero&&i==0?0:((s%pos[i+1])/pos[i]==2?s-pos[i]:s+pos[i]), zero&&i==0, jud&&i==up);
    }
    if(!jud) dp[l][s] = ans;
    return ans;
}
LL f(LL num){
    int pos=0;
    while(num){
        digit[++pos]=num%10;
        num/=10;
    }
    return dfs(pos,0,1,1);
}
int main()
{
    init();
    memset(dp, -1, sizeof(dp));
    int T;
    LL a, b;
    scanf("%d", &T);
    while(T--){
        scanf("%lld%lld", &a,&b);
        printf("%lld\n", f(b)-f(a-1));
    }
    return 0;
}