数位dp/三进制状压(SPOJ BALNUM Balanced Numbers )

对于这道题,我们设一位数有三个状态,

0:该位是前导零
1::该位是奇数
2:该位是偶数

最终仿照状压dp将状态压缩进dp数组二维。

dp[i][k] 前i位数字,状态为k的个数。

下面是ac代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
const int N = 1e5+5;
typedef unsigned long long ull;
ll f[30][60000];
int su[60];
int che(int sta)
{
    for (int i = 0; i <= 9; i++)
    {
        if ((i&1) && sta % 3 == 1)
            return 0;
        if (!(i&1) && sta%3 == 2)
            return 0;
        sta /= 3;
    }
    return 1;
}
int change(int sta, int i)
{
    int te = sta;
    int j = i;
    while(j--)
    {
        te /= 3;
    }
    int x = te % 3;
    if (x==0)
        sta += (int)pow(3.0, i);
    else if (x == 1)
        sta += (int)pow(3.0, i);
    else sta -= (int)pow(3.0, i);
    return sta;
}
ll dp(int cur, int sta, bool flag)
{
    if (!cur) return che(sta);
    if (!flag &&f[cur][sta] != -1) return f[cur][sta];
    ll ans = 0;
    int mx = flag?su[cur]:9;
    for (int i = 0; i <= mx; i++)
        ans += dp(cur-1, sta==0&&i==0?0:change(sta, i), flag&&i==mx);
    if (!flag) return f[cur][sta] = ans;
    return ans;
}
ll so(ll a)
{
    int len = 0;
    while(a)
    {
        su[++len] = a%10;
        a /= 10;
    }
    return dp(len, 0, 1);
}
int main()
{
    int t;
    cin >>t;
    memset(f, -1, sizeof(f));
    while(t--)
    {
        ll l, r;
        cin >> l >> r;
        cout << so(r) - so(l-1) << endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值