题意
T组测试数据,每次查询[L, R]区间内有多少个平衡数(Balanced Numbers)。
平衡数定义为:0,2,4,6,8每个数的出现次数为奇数,1,3,5,7,9每个数的出现次数为偶数。2201,不算,因为2出现了两次(偶数次),1出现了1次(奇数次)。
思路
依旧拿记忆化搜索来写数位DP,我们这次需要存下0~9每个数字有没有出现和出现次数的奇偶。
这个状态可以压缩为一个三进制数来表示。三进制的倒数第 i 位:为0表示 i 数字没出现,为1表示出现次数为奇数,2为偶数。
dp[pos][state]表示选到pos位置状态为state,后面数字随便选的方案数。
需要实现两个函数,①对状态state 加上一个数字 x 后的状态,②最终状态是否符合要求。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = pow(3, 11)+5;
typedef long long LL;
LL dp[20][MAXN];//第二维用三进制表示状态,0表示没有,1表示奇数,2表示偶数
string s;
int update(int state, int num)
{
int ans = 0, f = 1;
for (int i = 0; i <= 9; i++)
{
int x = state%3;
if (i == num) x = (x==1?2:1);
ans += f*x;
f *= 3; state /= 3;
}
return ans;
}
bool judge(int state)
{
int i = 0;
while (state)
{
int x = state%3;
if (i%2 == 1 && x == 1 || i%2 == 0 && x == 2) return false;
state /= 3;
i++;
}
return true;
}
LL dfs(int pos, int state, bool fzero, bool limit)
{
if (pos == -1) return judge(state);
if (!limit && dp[pos][state] != -1) return dp[pos][state];
int E = limit?s[pos]-'0':9;
LL ans = 0;
for (int i = 0; i <= E; i++)
{
ans += dfs(pos-1, (fzero&&(i==0))?0:update(state, i), fzero&&(i==0), limit&&(i==E));
}
if (!limit) dp[pos][state] = ans;
return ans;
}
LL solve(LL x)
{
s = to_string(x); reverse(s.begin(), s.end());
return dfs(s.size()-1, 0, 1, 1);
}
int main()
{
memset(dp, -1, sizeof(dp));
int T; scanf("%d", &T);
while (T--)
{
LL L, R; scanf("%lld%lld", &L, &R);
printf("%lld\n", solve(R)-solve(L-1));
}
return 0;
}
/*
2
1 1000
1 9
*/