·Balanced Numbers SPOJ - BALNUM

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> 
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long LL;
const LL mod=1e9+7;
const int M=13;
using namespace std;
const int N =1e5+100;
LL dp[21][60000];//dp[pos][sta]
int v[20],a[21];//v[i]表示3^i
LL K(int x) { //判断状态是否满足题意
    //三进制表示
    //0表示未出现,1表示出现了奇数次,2表示出现了偶数次
    for(int i=0; x&&i<=9; i++,x/=3) {
        //如果没有出现过
        if(x%3==0)
            continue;
        //如果出现奇数次
        else if(x%3==1) {
            //如果这一位是奇数,那么应该出现偶数次
            //
            if(i&1)
                return 0;
            //为2,出现偶数次
        } else {
            //如果当数字是偶数
            if(i%2==0)
                return 0;
        }
    }
    return 1;
}
//当前状态,i的次数+1
int getsta(int sta,int i) {
    //前导0
    if(i==0&&sta==0)
        return 0;//排除前导0的影响
    int x=(sta%(v[i]*3))/v[i];//x为数字i出现的状态
    //sta%(v[i]*3) 表示把第i为以上的去掉
    //再/v[i] 表示出现了几次
    if(x<=1)
        return sta+v[i];
    return sta-v[i];
}
//sta 当前数字的每一位的三进制表示
LL dfs(int pos,int sta,int limit) { //数位dp板子
    //搜到最后
    if(pos==-1)
        return K(sta);
    //之前已经搜到过,没有限制
    if(!limit&&dp[pos][sta]!=-1)
        return dp[pos][sta];
    //限制
    int up=limit?a[pos]:9;
    LL ans=0;
    for(int i=0; i<=up; i++)
        //当前状态,i的次数+1
        ans+=dfs(pos-1,getsta(sta,i),limit&&i==up);
    return limit?ans:dp[pos][sta]=ans;
}
LL slove(LL x) {
    int pos=0;
    for(; x; x/=10)
        a[pos++]=x%10;
    return dfs(pos-1,0,1);
}
int main() {
    mem(dp,-1);
    v[0]=1;
    //三进制表示
    for(int i=1; i<=10; i++)
        v[i]=v[i-1]*3;
    int t;
    scanf("%d",&t);
    while(t--) {
        LL l,r;
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",slove(r)-slove(l-1));
    }
}
上一篇:LeetCode开心刷题五十二天——110. Balanced Binary Tree


下一篇:837B. Balanced Substring