zoukankan      html  css  js  c++  java
  • 数位DP

    数位DP:

     以前遇到数位dp的题都是用其他的方法做的,这些遇到标准的数位dp的题就傻眼了。之前一道题计算1,2的个数,差点摸到数位dp的门槛了。

    入门资料

    基础题

    不要62

    #include <cstdio>
    #include <memory.h>
    
    int dp[8][3];
    //d[l][0]表示不存在不吉利数字 (包含d[l][1])
    //d[l][1]表示不存在不吉利数字,但首位是2 
    //d[l][2]表示存在不吉利的数字
    
    void init() {
        memset(dp, 0, sizeof dp);
        dp[0][0] = 1;
        for (int i = 1; i <= 7; ++i) {
            dp[i][0] = 9 * dp[i - 1][0] - dp[i - 1][1];
            dp[i][1] = dp[i - 1][0];
            //前面加4 ,或者 dp[i - 1][1]前面加6 
            dp[i][2] = 10 * dp[i - 1][2] + dp[i - 1][0] + dp[i - 1][1];
        } 
    }
    
    int sum(int t) {//统计0到t的不吉利的数的个数 
        int len = 0;
        int all = t;
        int digit[8] = {0}; 
        while (t) {
            digit[++len] = t % 10;
            t /= 10;
        }
        int ans = 0; //不吉利的数的个数 
        bool flag = false; //是否已成为不吉利的号 
        int last = 0;
        for (int i = len; i >= 0; --i) {
            ans += dp[i - 1][2] * digit[i];
            if (flag) ans += dp[i - 1][0] * digit[i];
            if (!flag && digit[i] > 4) //当前位可以为4 
                ans += dp[i - 1][0];
            if (!flag && digit[i] > 6) //当前位可以为2,4,6
                 ans += dp[i - 1][1]; //为6,则把前一位的2算上
            if (!flag && last == 6 && digit[i] > 2) //若上一位已经为6,当前位为2 
                ans += dp[i - 1][0]; 
            if(digit[i] == 4 || (last == 6 && digit[i] == 2))
                flag = true;
            last = digit[i];
        }
        return all - ans;
    } 
     
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
        int n, m;
        init();
        while (scanf("%d%d", &n, &m) != EOF && (n != 0 || m != 0)) {
            printf("%d
    ", sum(m + 1) - sum(n));
        } 
        return 0;
    }
    View Code

     题目:有趣的数

    问题描述

    我们把一个数称为有趣的,当且仅当:

    1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。

    2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。

    3. 最高位数字不为0。

    因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。

    请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。

    输入格式
    输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。
    输出格式
    输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。
    样例输入
    4
    样例输出
    3
    答案用的数位dp和记忆化搜索
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <deque>
    #include <list>
     
    using namespace std;
     
    long long f[2000][3][2]; // f[seq_k to place][0: to place 0 , 1: ethier 0 or 1, 2 : must be 1][3 is placed ? 1 : 0]
     
    int dp(int n, int p1, int p3)
    {
             long long &now = f[n][p1][p3];
             if (now != -1)
                       return now;
             if (n == 0)
             {
                       if (p1 == 2 && p3 == 1)
                       {
                                now = 1;
                       }else
                       {
                                now = 0;
                       }
                       return now;
             }
             now = 0;
             if (p1 == 0)
             {
                       now += dp(n-1, 1, p3); // go 0
             }else if (p1 == 1)
             {
                       now += dp(n-1, 1, p3); // go 0
                       now += dp(n-1, 2, p3); // go 1
             }else // p1 == 2
             {
                       now += dp(n-1, 2, p3); // go 1
             }
             
             if (p3 == 0)
             {
                       now += dp(n-1, p1, p3); // go 2;
                       now += dp(n-1, p1, 1); // go 3;
             }else
             {
                       now += dp(n-1, p1, 1); // go 3;
             }
             now %= 1000000007;
    }
     
    int main()
    {
             int n;
             cin >> n;
             memset(f, -1, sizeof(f));
             int ans = dp(n - 1, 0, 0); // seq[n] is 2
             cout << ans << endl;
             return 0;
    }
    View Code
     
  • 相关阅读:
    548
    zookeeper的异常处理(Disconnected, SyncConnected, Expired)
    ZOJ 2588 Burning Bridges(求含重边的无向连通图的割边)
    SQL Server 中VARCHAR(MAX)变量赋值引起的性能问题。
    查看mysql数据库版本方法总结
    Linux mysql 5.6: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
    Ignite用户配置管理介绍
    ORACLE动态采样分析
    SQL SERVER 2012链接到SQL SERVER 2000的问题解决案例
    SQL SERVER 2005删除维护作业报错:The DELETE statement conflicted with the REFERENCE constraint "FK_subplan_job_id"
  • 原文地址:https://www.cnblogs.com/fripside/p/3572269.html
Copyright © 2011-2022 走看看