题意
求区间[A,B]上的平衡数个数。平衡数是这样的数:在数的各个位上,奇数数字出现偶数次,偶数数字出现奇数次。
思路
很明显我们需要记录每一位出现的次数。分别记录是不明智的,而我们又只需要记录奇数次或者偶数次即可。所以我们可以用一个<=1024的数state表示0~9这10个数字出现的次数奇偶性,当奇数出现偶数次则相应位为1,当偶数出现奇数次相应位为1,最后判断是不是1023。但是这样它的初试状态不好确定。很明显初始时我们需要把state赋值成1010101010,即682(0次算偶次)。但是如果某些偶数位从始至终都没有出现,那么那一位最终为0显然不合理。我也没有想到什么更好的办法,只能再加一个1024的vis数表示0~9这10个数字是否出现过,但这样空间不够。后来想到一个优化是我们不必记录奇数是否出现过,因为它们初始就为1。所以可以把vis缩减到32,这样空间就足够了~问题边迎刃而解。
代码
[cpp]
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i, begin, m) for (int i = begin; i < begin+m; i ++)
using namespace std;
typedef long long LL;
typedef vector <int> VI;
typedef set <int> SETI;
typedef queue <int> QI;
typedef stack <int> SI;
LL dp[20][1050][35][2];
VI num;
LL dfs(int pos, int state, int vis, bool flag, bool limit){
if (pos == -1){
bool ok = 1;
for (int i = 0; i <= 9; i ++)
if ((state & (1<<i)) == 0){
if (i % 2) {ok = 0; break;}
else if ((vis & (1 << (i/2))) != 0){
ok = 0; break;
}
}
return ok;
}
if (!limit && ~dp[pos][state][vis][flag]) return dp[pos][state][vis][flag];
int end = limit?num[pos]:9;
LL res = 0;
for (int i = 0; i <= end; i ++){
int next_state, next_vis;
if (i == 0 && !flag){
if (pos == 0){
next_state = state | 1;
next_vis = vis|1;
}
else{
next_state = state;
next_vis = vis;
}
}
else{
next_state = state ^ (1<<i);
if (i % 2 == 0)
next_vis = vis|(1<<(i/2));
else
next_vis = vis;
}
res += dfs(pos-1, next_state, next_vis, (!flag)&&i==0?flag:true, limit && (i==end));
}
return limit?res:dp[pos][state][vis][flag] = res;
}
LL cal(LL x){
num.clear();
while(x){
num.push_back(x%10);
x /= 10;
}
int len = num.size();
return dfs(len-1, 682, 0, 0, 1);
}
int main(){
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
MEM(dp, -1);
int t;
scanf("%d", &t);
while(t --){
LL a, b;
scanf("%lld %lld", &a, &b);
printf("%lld
", cal(b)-cal(a-1));
}
// for (int i = 100; i <= 1000; i ++){
// if (cal(i)-cal(i-1) == 1)
// printf("i = %d
", i);
// }
return 0;
}
[/cpp]