zoukankan      html  css  js  c++  java
  • CF1277A. Happy Birthday, Polycarp! 题解 枚举/数位DP

    题目链接:http://codeforces.com/contest/1277/problem/A

    题目大意:
    求区间 ([1,n]) 范围内有多少只包含一个数字的数。
    比如:(1,77,777,44,999999) 都是只包含一个数字的数,而 (12,11110,6969,987654321) 这些不是。

    解题思路:
    本题可以采用枚举和数位DP解法来解决(当然,数位DP相对来说有些杀鸡用牛刀的感觉)。

    枚举解法

    首先,我们要确定,去除 (0) 以外,一个 (i) 位数最多有 (9) 个这样的数:

    • (1)位数中总共有 (9) 个符合要求的数:(1,2,3,4,5,6,7,8,9)
    • (2)位数中总共有 (9) 个符合要求的数:(11,22,33,44,55,66,77,88,99)
    • (3)位数中总共有 (9) 个符合要求的数:(111,222,333,444,555,666,777,888,999)
    • ……

    因为告诉我们 (1 le n le 10^9) ,所以我们最多考虑 (9) 位数即可。

    也就是说,所有满足要求的数只有 (9 imes 9 = 81) 个,我们只需要枚举这 (81) 个数,然后判断有多少个 (le n) 即可。

    实现代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int T, n;
    int solve() {
        int cnt = 0;
        for (int i = 1; i <= 9; i ++) {
            int s = 0;
            for (int j = 0; j < 9; j ++) {
                s = s * 10 + i;
                if (s > n) break;
                cnt ++;
            }
        }
        return cnt;
    }
    int main() {
        cin >> T;
        while (T --) {
            cin >> n;
            cout << solve() << endl;
        }
        return 0;
    }
    

    数位DP解法

    我们定义状态 (f[pos][pre]) 表示当

    • 点前所在的数位为第 (pos) 位,
    • 前一位放置的元素是 (pre)(如果前一位没有放置任何元素则 (pre=0)

    时的方案总数。

    并且开函数 dfs(int pos, int pre, bool limit) 用于求解:

    • 点前所在的数位为第 (pos) 位;
    • 前一位放置的元素是 (pre)(如果前一位没有放置任何元素则 (pre=0));
    • (limit) 用于表示当前是否处于闲置转态

    时的方案总数。

    但是最终答案因为包含 (0) 这个方案,所以要减去 (1)

    实现代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int f[11][11], T, n, a[11];
    void init() {
        memset(f, -1, sizeof(f));
    }
    int dfs(int pos, int pre, bool limit) {
        if (pos < 0) return 1;
        if (!limit && f[pos][pre] != -1) return f[pos][pre];
        int up = limit ? a[pos] : 9;
        int tmp = 0;
        for (int i = 0; i <= up; i ++) {
            if (pre == 0) {
                if (i == 0) tmp += dfs(pos-1, i, limit && i==up);
                else tmp += dfs(pos-1, i, limit && i==up);
            }
            else if (i == pre) tmp += dfs(pos-1, i, limit && i==up);
        }
        if (!limit) f[pos][pre] = tmp;
        return tmp;
    }
    int get_num(int x) {
        int pos = 0;
        while (x) {
            a[pos++] = x%10;
            x /= 10;
        }
        return dfs(pos-1, 0, true);
    }
    int main() {
        init();
        cin >> T;
        while (T --) {
            cin >> n;
            cout << get_num(n)-1 << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    .net反编译原理
    科学使用Log4View2
    头条一面竟然问我Maven?
    SpringCloud Netflix(一) :微服务架构
    Linux环境安装Docker
    Quartz定时任务
    Jedis连接外部Redis
    宝塔phpmyadmin打不开的可能问题及解决方法
    文件上传 Window & Linux
    SpringBoot登录判断
  • 原文地址:https://www.cnblogs.com/quanjun/p/12041358.html
Copyright © 2011-2022 走看看