SPOJ 10606. Balanced Numbers (数位DP)

题目链接:http://www.spoj.com/problems/BALNUM/

 

 

 

这题要求出现的数字,偶数出现奇数次,奇数出现偶数次。

用三进制表示0~9的状态

//============================================================================

// Name        : SPOJ.cpp

// Author      : 

// Version     :

// Copyright   : Your copyright notice

// Description : Hello World in C++, Ansi-style

//============================================================================



#include <iostream>

#include <stdio.h>

#include <string.h>

#include <algorithm>

using namespace std;

long long dp[20][60000];

//3进制表示数字0~9的出现情况,0表示没有出现,1表示奇数次,2表示偶数次

int bit[20];

bool check(int s)

{

    int num[10];

    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 false;

            if(i%2==1 && num[i]==1)return false;

        }

    return true;

}

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 news=0;

    for(int i=9;i>=0;i--)

    {

        news*=3;

        news+=num[i];

    }

    return news;

}

long long dfs(int pos,int s,bool flag,bool z)

{

    if(pos==-1)return check(s);

    if(!flag && dp[pos][s]!=-1)

        return dp[pos][s];

    long long ans=0;

    int end=flag?bit[pos]:9;

    for(int i=0;i<=end;i++)

        ans+=dfs(pos-1,(z&&i==0)?0:getnews(i,s),flag&&i==end,z&&i==0);

    if(!flag)dp[pos][s]=ans;

    return ans;

}

long long calc(long long n)

{

    int len=0;

    while(n)

    {

        bit[len++]=n%10;

        n/=10;

    }

    return dfs(len-1,0,1,1);

}

int main()

{

    //freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    int T;

    memset(dp,-1,sizeof(dp));

    long long a,b;

    scanf("%d",&T);

    while(T--)

    {

        cin>>a>>b;

        cout<<calc(b)-calc(a-1)<<endl;

    }

    return 0;

}

 

你可能感兴趣的:(number)