Balanced Numbers SPOJ - BALNUM

Balanced Numbers SPOJ - BALNUM (数位dp)

题目链接:https://cn.vjudge.net/contest/163023#problem/J
题目大意:
问A到B之间有多少个数,有多少数 符合以下两个条件。
数位0-9 中 ,每一个奇数数位有 偶数个, 偶数数位有奇数个。也就是如果有1 的话,那必须有偶数个1。如果有2的话,必须有奇数个2,当然没有也可以。
题目分析:问A到B之间有多少个数,有多少数 符合以下两个条件。
数位0-9 中 ,每一个奇数数位有 偶数个, 偶数数位有奇数个。
也就是如果有1 的话,那必须有偶数个1。如果有2的话,必须有奇数个2,当然没有也可以。注意前导零是不能算的。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll dp[30][60000];
int data[30];

bool judge(int s)
{
    for(int i = 0; i <= 9; i++) //依次去判断每一位
    {
        if((s % 3 == 1) && (i & 1)) return false;
        if((s % 3 == 2) && !(i & 1)) return false;
        s /= 3;
    }
    return true;
}

int cal(int now, int x)
{
    int num = x, tmp = now;
    while(num--)//找到x对应的那一位
    {
        tmp /= 3;
    }


    tmp %= 3; //计算有多少个x
    if(tmp == 0 || tmp == 1) now += (int)pow(3.0, x); //当前位变为奇数
    else now -= (int)pow(3.0, x); //当前位变为偶数数

    return now;
}

ll dfs(int pos, int s, bool limit)
{
    if(pos == -1) return judge(s);
    if(!limit && dp[pos][s] != -1) return dp[pos][s];
    int up = limit ? data[pos] : 9;
    ll ans = 0;

    for(int i = 0; i <= up; i++)
    {
        ans += dfs(pos - 1, (s == 0 && i == 0) ? 0 : cal(s, i), i == data[pos] && limit);
    }
    if(!limit) dp[pos][s] = ans;
    return ans;
}

ll solve(ll n)
{
    int pos = 0;
    while(n)
    {
        data[pos++] = n % 10;
        n /= 10;
    }
    return dfs(pos - 1, 0, true);
}

int main()
{
    int t;
    memset(dp, -1, sizeof(dp));
    scanf("%d", &t);
    while(t--)
    {
        ll a, b;
        scanf("%lld %lld", &a, &b);
        printf("%lld\n", solve(b) - solve(a - 1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/deerly_/article/details/79927520