SPOJ ~ BALNUM ~ Balanced Numbers (数位DP + 状压)

 

题意

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
*/

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值