SPOJ - BALNUM 数位dp

题意:求某一区间内的平衡数个数(指一个数,其中出现过的数,如果是偶数,那么必须出现奇数次,反之偶数次)

题解:用三进制来枚举(0到9)所有情况,0代表没有出现,1代表出现奇数次,2代表出现偶数次dp【i】【j】i代表位数,j代表状态,在记忆化搜索的时候要记录0是否出现过

(因为之前很少写3进制的状态,写的大多数是2进制的,所以很不熟练,还是要多练,刚开始是把题意理解错了,以为是所有的奇数出现偶数次 这样,所以搞了半天也不对)

#include<bits/stdc++.h>
#define C 0.5772156649
#define pi acos(-1.0)
#define ll long long
#define mod 1000000007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;

const double g=10.0,eps=1e-7;
const int N=20+10,maxn=60000+10,inf=0x3f3f3f;

int digit[N];
ll dp[N][maxn];
bool check(int s)
{
    int num[20];
    for(int i=0;i<10;i++)
    {
        num[i]=s%3;
        s/=3;
    }
    for(int i=0;i<10;i++)
    {
        if(num[i]!=0)
        {
            if(i%2==0&&num[i]==2)return 0;
            if(i%2==1&&num[i]==1)return 0;
        }
    }
    return 1;
}
int getnews(int x,int s)
{
    int num[10];
    for(int i=0;i<10;i++)
    {
        num[i]=s%3;
        s/=3;
    }
    if(num[x]==0)num[x]=1;
    else num[x]=3-num[x];
    int ans=0;
    for(int i=9;i>=0;i--)
    {
        ans*=3;
        ans+=num[i];
    }
    return ans;
}
ll dfs(int len,int s,bool ok,bool fp)
{
    if(!len)
    {
        if(check(s))return 1;
        return 0;
    }
    if(!fp&&dp[len][s]!=-1)return dp[len][s];
    ll ans=0,fpmax=fp ? digit[len] : 9;
    for(int i=0;i<=fpmax;i++)
    {
        ans+=dfs(len-1,(ok&&i==0)?0:getnews(i,s),ok&&i==0,fp&&i==fpmax);
    }
    if(!fp)dp[len][s]=ans;
    return ans;
}
ll solve(ll x)
{
    int len=0;
    while(x)
    {
        digit[++len]=x%10;
        x/=10;
    }
    return dfs(len,0,1,1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    memset(dp,-1,sizeof dp);
    while(t--)
    {
        ll l,r;
        cin>>l>>r;
        cout<<solve(r)-solve(l-1)<<endl;
    }
    return 0;
}
/********************

********************/
View Code

 

posted @ 2017-09-01 15:18  walfy  阅读(200)  评论(0编辑  收藏  举报