SPOJ---BALNUM:Balanced Numbers(数位dp+状压)

题意:

定义平衡数:一个十进制数的十进制位中,每个奇数出现偶数次,每个偶数出现奇数次,求区间内平衡数的个数

分析:

我们要统计每个数字出现的次数,考虑状压,因为数字只有0~9,每个数字有三种状态:没有出现,出现奇数次,出现偶数次,所以用三进制状压,还要考虑前导0

代码:

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
typedef unsigned long long LL;
LL dit[22],dp[22][60000],vis[22]; // vis数组模拟3进制
LL p[10]={1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683};
LL check()
{
    for(int i = 0;i < 10; ++i)
    {
        if(!vis[i]) continue;
        if((i&1) && (vis[i]&1)) return 0;
        if(!(i&1) && !(vis[i]&1)) return 0;
    }
    return 1;
}
LL dfs(int pos,int v,int pre,int limit)
{
    if(pos < 0) return check();
    if(!limit && dp[pos][v]) return dp[pos][v];
    int up = limit ? dit[pos] : 9;
    LL res = 0;
    for(int i = 0;i <= up; ++i)
    {
        int vv = v - vis[i] * p[i],tep = vis[i],np = pre;
        if((i==0 && !pre) || i){
        if(!vis[i]) vis[i] = 1;
        else if(vis[i] == 1) vis[i] = 2;
        else vis[i] = 1;
        vv += vis[i] * p[i];}
        if(pre && i) np = 0; 
        res += dfs(pos-1,vv,np,limit && i==dit[pos]);
        vis[i] = tep;
    }
    if(!limit) dp[pos][v] = res;
    return res;
}
LL solve(LL x)
{
    int len = 0;
    while(x)
    {
        dit[len++] = x % 10;
        x /= 10;
    }
    return dfs(len-1,0,1,1);
}
int main()
{

    LL l,r,T;
    scanf("%llu",&T);
    while(T--)
    {
        scanf("%llu %llu",&l,&r);
        printf("%llu\n", solve(r) - solve(l-1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/87870284
今日推荐