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

来源:互联网 发布:link域名可以备案吗 编辑:程序博客网 时间:2024/06/04 18:58

Description

A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and nm ≤ 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 nm ≤ 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 11100 2000 5001234567890 23456789010 4294967295-1 -1

Sample Output

122929876543043825876150

题意:让你统计区间里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;}


0 0