首页 > 代码库 > 数位DP小小结

数位DP小小结

FZOJ Problem 2113 Jason的特殊爱好

题意:x~y数字里面有多少个 1 

思路:我们算法课实验题的简化版,当时我用了很麻烦的一个DP=_=

刚刚学到了很棒的姿势,记忆化DP!!

dfs(int pos ,bool end1) ;

end1==false 返回pos位后面(包含pos)任意组合有多少个 1 ;

end1==true 返回上一位是结尾,Pos以后的位受到限制组合有多少个 1 ;

大概是这样,如果数字是 4987 现在计算到 8 这个数字,end1==true,说明是49XX

XX的取值是0-87;

如果计算到当前位,如果是这位是1 ,如果没有限制,那么答案就是加上10^pos个

如果有限制,那么答案就是加上nn%(10^pos)+1 个,

如果不是结尾(也就是没有限制的),我们可以dp[pos]保存计算过的结果。

include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long long#define ll long long#define INF 0x3f3f3f3f#define maxn 50010#define eps 1e-6#define mod 1000000007using namespace std;LL dp[30] ,nn ;int bit[30] ;LL get1(int pos){    LL tt=1;    for(int i=0;i<pos;i++)        tt *= 10;    return nn%tt;}LL get2(int pos){    LL tt=1;    for(int i=0;i<pos;i++)        tt *= 10;    return tt;}LL dfs(int pos ,bool end1){    if(pos==-1)    {        return 0;    }    if(!end1&&dp[pos] != -1)    {        return dp[pos];    }    int e ,ee ;    LL ans=0;    if(end1) e = bit[pos] ;    else e = 9 ;    for(int i = 0 ; i <= e ;i++)    {        if(i==1){             if(i==e)ans += get1(pos)+1;             else ans += get2(pos) ;        }        ans += dfs(pos-1,(end1&&i==e)) ;    }    if(!end1)    {        dp[pos] = ans;    }    return ans;}LL getans(LL n ){    nn=n;    int len=0;    if(n<=0) return 0 ;    while(n)    {        bit[len++] = n%10 ;        n /= 10 ;    }    LL ans=0;    ans = dfs(len-1,1) ;    return ans;}int main(){    int i , j , m ,k ,T ;    LL x,y ;    memset(dp,-1,sizeof(dp)) ;   // cout << getans(20)<<endl;    while(cin >> x >> y)    {        y=getans(y) ;        x=getans(x-1);        cout << y-x<< endl;    }    return 0 ;}
View Code

hdu 3555 Bomb

题意:x~y数字里面有多少个49 

思路:和上面做法差不多,只是多了一个状态

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long long#define ll long long#define INF 0x3f3f3f3f#define maxn 50010#define eps 1e-6#define mod 1000000007using namespace std;LL dp[30][20] ,nn ;int bit[30] ;LL dfs(int pos ,int num ,bool end1){    if(pos==-1)    {        return num==2 ;    }    if(!end1&&dp[pos][num] != -1)    {        return dp[pos][num];    }    int e,ee;    LL ans=0;    if(end1) e = bit[pos] ;    else e = 9 ;    for(int i = 0 ; i <= e ;i++)    {        if(num==1&&i==9)        {            ee=2;        }        else if(num==0&&i==4)        {            ee=1;        }        else if(num==1&&i != 4)        {            ee=0;        }        else ee=num ;        ans += dfs(pos-1,ee,(end1&&i==e)) ;    }    if(!end1)    {        dp[pos][num] = ans;    }    return ans;}LL getans(LL n ){    nn=n;    int len=0;    if(n<=0) return 0 ;    while(n)    {        bit[len++] = n%10 ;        n /= 10 ;    }    LL ans=0;    ans = dfs(len-1,0,1) ;    return ans;}int main(){    int i , j , m ,k ,T ;    LL x,y ;    memset(dp,-1,sizeof(dp)) ;   // cout << getans(20)<<endl;    cin >> T ;    while(cin >> y)    {        y=getans(y) ;        cout << y<< endl;    }    return 0 ;}
View Code

hdu 3709 Balanced Number

题意:x-y有多少个是平衡的,平衡的定义是,找一个支点,使得两边的重量一样

思路:  还是和上面的姿势一样,只是状态多了一些~~~

对于  dfs(int pos ,int v,int val,bool end1)

if(end1==false)表示当前计算到第pos位,选的支点为v,前面比后面的重val,后面pos位任意组合

返回的数字数目。

if(end1==true)也就是有限制了

include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long long#define ll long long#define INF 0x3f3f3f3f#define maxn 50010#define eps 1e-6#define mod 1000000007using namespace std;LL dp[20][20][2000] ;int bit[30] ;LL dfs(int pos ,int v,int val,bool end1){    if(pos==-1)    {        return (val==0) ;    }    if(!end1&&dp[pos][v][val] != -1)    {        return dp[pos][v][val] ;    }    if(val<0) return 0 ;    int e ,ee ;    LL ans=0;    if(end1) e = bit[pos] ;    else e = 9 ;    for(int i = 0 ; i <= e ;i++)    {        ee = val+(pos-v)*i ;        ans += dfs(pos-1,v,ee,(end1&&i==e)) ;    }    if(!end1)    {        dp[pos][v][val] = ans;    }    return ans;}LL getans(LL n ){    int len=0;    if(n<0) return 0 ;    while(n)    {        bit[len++] = n%10 ;        n /= 10 ;    }    LL ans=0;    for( int i = 0 ; i <len ;i++)    {        ans += dfs(len-1,i,0,1) ;    }    return ans-(len-1) ;}int main(){    int i , j , m ,k ,T ;    LL x,y ;    memset(dp,-1,sizeof(dp)) ;    cin >> T ;    while(T--)    {        cin >> x >> y ;        y=getans(y) ;        x=getans(x-1);        cout << y-x<< endl;    }    return 0 ;}
View Code

 

数位DP小小结