• 数位dp


    1、 hdoj 2089 不要62

    题意: 不吉利数为数中含有4或者62,  单个6或者单个2或者26都不是不吉利数; 求给定区间里的吉利数;

    //代码1 ; 
    #include <cstdio>
    #define MAXN 10
    #include <cstring>
    using namespace std;
    int dp[MAXN][3];
    
    // dp[i][0] 长度为i, 不含有不吉利数字                     <1>
    // dp[i][1] 长度为i, 不存在不吉利数字, 且最高位为2;        <1>
    // dp[i][2] 长度为i, 含有不吉利数字                       <2>
    void init()
    {
        dp[0][0]=1;   
        dp[0][1]=dp[0][2]=0;
        for(int i=1; i<= 10; i++)
        {
            dp[i][0]= dp[i-1][0]*9 - dp[i-1][1];  //在最高位 加上除4以外的9个数字, 但要减去2之前加上6的情况; 
            dp[i][1]= dp[i-1][0];                 //在不含不吉利数的最高位加上2 ; 
            dp[i][2]= dp[i-1][2]*10 + dp[i-1][0] + dp[i-1][1]; //在已有不吉利数的最高位加上(1~9)任意数字 + 无不吉利数的最高位加上4 + 2前面加上6; 
        }    
    }
    
    int bit[MAXN];
    int solve(int n)
    {
        int len=0;
        memset(bit, 0, sizeof(bit));
        int tmp=n;
        while(n)
        {
            bit[++len]= n%10;
            n /= 10; 
        } 
        int ans=0;
        int flag=0;
        for(int i=len; i>=1; i--)
        {
            ans= ans + bit[i]*dp[i-1][2];     //由上位所有不吉利数推导; (不含前导零, 所以乘以bit[i];);  
            if(flag) ans+= bit[i]*dp[i-1][0]; //之前出现的不吉利数字 ; 
            else
            {
                if(bit[i] >4) ans +=dp[i-1][0];  //最高位将会出现4; 
                if(bit[i] >6) ans +=dp[i-1][1];  //i-1长度的最高位已经为2, 6将会加到最高位;  
                if(bit[i+1]== 6 && bit[i] >2) ans +=dp[i][1];  //出现62 ; 
            }
            if(bit[i+1] ==6&& bit[i]==2) flag =1;
            if(bit[i]== 4) flag=1;
        }
        if(flag) ans++;
        return tmp-ans;  //所有的数减去不吉利数 ; 
    }
    int main()
    {
        int n, m;
        init();
        while(scanf("%d%d", &n, &m) != EOF)
        {
            if(!n && !m) break;
            int ans=solve(m)- solve(n-1);
            printf("%d
    ", ans);
        }
        return 0;
    }
    //记忆化搜索(不好理解!! );
    #include <cstdio>
    #include <cstring>
    const int N = 10;
    using namespace std ;
    
    int bit[N];
    int dp[N][2];// dp[i][is6] is the number of i-len digits with (if prevent number is 6), its digits are from 0-9  
    int dfs(int len, bool is6, bool ismax)
    {
        if(len==0) return 1;
        if(!ismax && dp[len][is6] >= 0) return dp[len][is6];
        
        int cnt=0;
        int Max= ismax? bit[len]: 9;
        for(int i=0; i<= Max; i++)     //枚举数位 ; 
        {
            if(i==4 || is6 && i == 2)  // unluck digit 
                continue;
            cnt += dfs(len-1, i==6, ismax && i==Max);
        }
        return ismax? cnt: dp[len][is6]= cnt;
    }
    
    int solve(int num)
    {
        int len=0;
        while(num)
        {
            bit[++len]=num%10;
            num /= 10;
        }
        return dfs(len, false, true);
    }
    
    int main()
    {
        int n, m;
        while(scanf("%d%d", &n, &m) != EOF)
        {
            if(!n && !m) break;
            memset(dp, -1, sizeof(dp));
            printf("%d
    ", solve(m)-solve(n-1));
        }
        return 0;
    }

    2、 hdoj 3555 Bomb

    给一个区间中含有49的数的个数,  4, 9必须相邻 ; (神奇的姿势,  找啊找啊找不同)

    #include <cstdio>
    #include <cstring>
    const int N = 21; 
    typedef long long LL;
    LL dp[N][3];
    //dp[i][0]; 不含49;   
    //dp[i][1]; 最高位为9; 
    //dp[i][2]; 含有49 ; 
    using namespace std;
    void init()    /***/
    {
        dp[0][0]=1;
        dp[0][1]=0; dp[0][2]=0;
        for(int i=1; i<=N; i++)
        {
            dp[i][0]=dp[i-1][0]*10-dp[i-1][1];
            dp[i][1]=dp[i-1][0];
            dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; 
        } 
    }
    
    int bit[N];
    LL solve(LL n)
    {
        int len=0;
        memset(bit, 0, sizeof(bit));
        while(n)
        {
            bit[++len]=n%10;
            n /= 10;
        }
        bit[len+1]=0;
        LL ans=0;
        int flag=0;
        for(int i=len; i>=1; i--)
        {
            ans=ans+bit[i]*dp[i-1][2];
            if(flag) ans=ans+ bit[i]*dp[i-1][0];
            else
            {
                if(bit[i]> 4) ans += dp[i-1][1];
                if(bit[i+1]==4 && bit[i]>9) ans += dp[i][1];
            }
            if(bit[i+1]==4 && bit[i]== 9) flag=1;
        }
        if(flag) ans++;
        return ans;
    }
    int main()
    {
        int t; LL N; init();
        scanf("%d", &t);
        while(t--)
        {
            scanf("%lld", &N);
            printf("%I64d
    ", solve(N)-solve(0));
        } 
        return 0;
    }

    3、UEST Cwindy数

    题意: 相邻数位大小<=2的数的个数 ;

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    inline int abs(int a){
        return a<0? a*(-1):a;
    }
    int dp[15][10]; //dp[i][j]表示长度为i, 最高位为j的windy的个数 ;
    void init()
    {
        memset(dp, 0, sizeof(dp));
        for(int i=0; i< 10; i++)
            dp[1][i]=1;
        for(int i=2; i<=10; i++)
            for(int j=0; j< 10; j++){
                for(int k=0; k<= j-2; k++)  //最高位加一位
                    dp[i][j] += dp[i-1][k];
                for(int k=j+2; k<10; k++)
                    dp[i][j] += dp[i-1][k];
            }
    } 
    
    int bit[20];
    int solve(int n){
        if(n==0) return 0;
        int len=0;
        while(n)
        {
            bit[++len]= n%10;
            n /=10;
        }
        bit[len+1]= -10;
        int ans=0; bool flag= true;
        for(int i=1; i< len; i++)
            for(int j=1; j<= 9; j++)
                ans +=dp[i][j];
        for(int j=1; j<bit[len];j++)
            ans += dp[len][j]; 
        for(int i=len-1; i>= 1; i--)
        {
            for(int j=0; j<bit[i]; j++)
                if(abs(bit[i+1]- j) >= 2)
                    ans+= dp[i][j]; 
            if(abs(bit[i+1]- bit[i])< 2)
            {
                flag= false ; 
                break;
            }
        }
        if(flag) ans++;
        return ans;
    }
    int main ()
    {
        int a, b; init();
        while(scanf("%d%d", &a, &b) != EOF)
        {
            printf("%d
    ", solve(b)- solve(a-1));
        }
        return 0;
    }
  • 相关阅读:
    sql -- 获取商品分类的最新销售情况
    sql -- 获取连续签到的用户列表
    sql -- 利用order by 排名作弊
    sql -- update表子查询、多条件判断case when
    sql-- 找到重复数据并删除、有重复数据不插入或更新的处理方法
    sql--自链接(推荐人)
    sql--测试商品的重要度,是否需要及时补货
    sql面试题
    TCP/IP 3次握手
    REST和SOAP
  • 原文地址:https://www.cnblogs.com/soTired/p/5379923.html
Copyright © 2020-2023  润新知