0%

SPOJ BALNUM

定义一个数为平衡数,当且仅当在它的每个十进制位上满足如下条件:

  1. 奇数出现的次数为偶数次

  2. 偶数出现的次数为奇数次

现有T个询问,每次询问闭区间[A,B]包含多少平衡数。

输入描述:

第一行一个T。T<=500
以下T行,每行两个数A,B。1<=A,B<=10^19

输出描述:

对于每个询问输出[A,B]区间包含多少平衡数。

示例1
输入

2
1 1000
1 9

输出

147
4

说明

T<=500, 1<=A,B<=10^19

SPOJ_BALLNUM.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<bits/stdc++.h>
using namespace std;
#define uLL unsigned long long
uLL dp[21][1025][1025];
int num[21];
bool mark[1025][1025];
bool check(int mask,int x){
if(!mask)return 0;
for(int i=0;i<10;i++)
if(mask&(1<<i)){
if(((x&(1<<i))>0)==(i&1))return 0;
}
return 1;
}
void Init(){
for(int i=0;i<1024;i++){
for(int j=0;j<1024;j++)
mark[i][j]=check(i,j);
}
}
uLL dfs(int pos,int mask,int x,bool limit){
if(pos==0)return mark[mask][x];
if(!limit&&~dp[pos][mask][x])return dp[pos][mask][x];
int up=limit?num[pos]:9;
uLL cnt=0;
for(int i=0;i<=up;i++){
if(!mask&&!i)cnt+=dfs(pos-1,mask,x,limit&&(i==up));
else cnt+=dfs(pos-1,mask|(1<<i),x^(1<<i),limit&&(i==up));
}
return limit?cnt:dp[pos][mask][x]=cnt;
}
uLL solve(uLL n){
if(n==0)return 0;
int len=0;
while(n){
num[++len]=n%10;
n/=10;
}
return dfs(len,0,0,1);
}
int main(){
Init();
int cas;
memset(dp,-1,sizeof(dp));
cin>>cas;
uLL L,R;
while(cas--){
cin>>L>>R;
cout<<solve(R)-solve(L-1)<<endl;
}
return 0;
}