数位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 1000000007
using 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 1000000007
using 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 1000000007
using 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
原文地址:https://www.cnblogs.com/20120125llcai/p/4066259.html