您的位置:首页 > 其它

POJ 3286 How many 0's?(数位DP)

2015-07-13 19:09 381 查看
Description

A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and n, m ≤ n. How many 0's will he write down?

Input

Input consists of a sequence of lines. Each line contains two unsigned 32-bit integers m and n, m ≤ n. The last line of input has the value of m negative and this line should not be processed.

Output

For each line of input print one line of output with one integer number giving the number of 0's written down by the monk.

Sample Input

10 11
100 200
0 500
1234567890 2345678901
0 4294967295
-1 -1


Sample Output

1
22
92
987654304
3825876150


题意:让你统计区间里0的个数。
分析:数位DP,开始想不好如何记忆化,神牛Alex想了一个机智的做法,因为对于一个32位数来说,
0的个数肯定不会大于32个,所以我们只需要枚举0的个数(1~32)进行数位DP就行了,那么对于这一类问题
都可以这样搞。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
const int INF=0x3f3f3f3f;
typedef long long LL;
LL a,b;
int m;
int num[40];
LL dp[40][40][2][40];
LL dfs(int pos,int have,int first,int flag)
{
    if(have<0)
        return 0;
    if(!pos)
        return have==0;
    if(!flag&&dp[pos][have][first][m]!=-1)
        return dp[pos][have][first][m];
    int ed=flag?num[pos]:9;
    LL res=0;
    for(int i=0;i<=ed;i++)
    {
        if(have>0&&!first&&i)
            res+=dfs(pos-1,have,1,flag&&i==ed);
        else if(have>0&&first&&!i)
            res+=dfs(pos-1,have-1,first,flag&&i==ed);
        else if(have<=0&&first&&!i)
            res+=dfs(pos-1,have-1,first,flag&&i==ed);
        else
            res+=dfs(pos-1,have,first,flag&&i==ed);
    }
    if(!flag)
        dp[pos][have][first][m]=res;
    return res;
}
LL solve(LL x)
{
    if(x==0)
        return 1;
    if(x<0)
        return 0;
    int pos=0;
    while(x)
    {
        num[++pos]=x%10;
        x/=10;
    }
    LL res=0;
    for(int i=1;i<=32;i++)
    {
        m=i;
        res+=i*dfs(pos,m,0,1);//pos,have,first,flag
    }
    return res+1;
}
int main()
{
    CLEAR(dp,-1);
    while(~scanf("%lld%lld",&a,&b))
    {
        if(a<0) break;
        LL ans=solve(b)-solve(a-1);
        printf("%lld\n",ans);
    }
    return 0;
}


顺带AC一下Light OJ 1032想同的思路

A bit is a binary digit, taking a logical value of either 1 or 0 (also referred to as "true" or "false" respectively). And every decimal number has a binary representation which is actually a series of bits. If a bit of
a number is 1 and its next bit is also 1 then we can say that the number has a 1 adjacent bit. And you have to find out how many times this scenario occurs for all numbers up to N.

Examples:

Number Binary Adjacent Bits

12 1100 1

15 1111 3

27 11011 2

Input

Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains an integer N (0 ≤ N < 231).

Output

For each test case, print the case number and the summation of all adjacent bits from 0 to N.

Sample Input

Output for Sample Input

7

0

6

15

20

21

22

2147483647

Case 1: 0

Case 2: 2

Case 3: 12

Case 4: 13

Case 5: 13

Case 6: 14

Case 7: 16106127360

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
const int INF=0x3f3f3f3f;
typedef long long LL;
int t,num[60];
LL n,m;
LL dp[40][2][40][40];
LL dfs(int pos,int pre,int have,int flag)
{
    if(have<0)
        return 0;
    if(!pos)
       return have==0;
    if(!flag&&dp[pos][pre][have][m]!=-1)
        return dp[pos][pre][have][m];
    int ed=flag?num[pos]:1;
    LL res=0;
    for(int i=0;i<=ed;i++)
    {
        if(have>0&&(i&pre))
            res+=dfs(pos-1,i,have-1,flag&&i==ed);
        else if(have<=0&&(i&&pre))
            res+=dfs(pos-1,i,have-1,flag&&i==ed);
        else res+=dfs(pos-1,i,have,flag&&i==ed);
    }
    if(!flag) dp[pos][pre][have][m]=res;
    return res;
}
LL solve(LL x)
{
    int pos=0;
    while(x)
    {
        num[++pos]=x%2;
        x/=2;
    }
    LL ans=0;
    for(int i=1;i<=32;i++)
    {
        m=i;
        ans+=dfs(pos,0,i,1)*i;//pos,pre,have,flag
    }
    return ans;
}
int main()
{
    int cas=1;
    scanf("%d",&t);
    CLEAR(dp,-1);
    while(t--)
    {
        scanf("%lld",&n);
        LL ans=solve(n);
        printf("Case %d: %lld\n",cas++,ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: