• HDU4507 吉哥系列故事——恨7不成妻 题解 数位DP


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4507

    题目大意:
    找到区间 ([L,R]) 范围内所有满足如下条件的数的 平方和

    • 不包含‘7’;
    • 不能被 7 整除;
    • 各位之和不能被 7 整除。

    注意:求的是满足条件的数的 平方和

    解题思路:
    使用 数位DP 尽情求解。
    但是因为这里求的是满足要求的元素的平方和,而不是元素的个数。
    所以我们不能简单地开long long来存放结果,
    而是开一个结构体来存放结果,结构体中需要包含三个元素:

    • 满足要求的元素个数(用 cnt 表示);
    • 满足要求的元素的和(用 sum 表示);
    • 满足要求的元素的平方和(用 sum2 表示)

    定义状态 (f[pos][pre][ts]) 表示:

    • 当前在第 (pos) 位;
    • 前一位(即第 (pos+1) 位)放置的数 mod 7为 (pre)
    • 前面所有位上的数的和 mod 7 的结果为 (ts)

    时对应的信息(包括元素个数、和、平方和)。

    那么如何获得状态转移方程呢?

    每次查找的数字的前几位都是一样的,比如对于三位数:

    [abc ]

    假设第一位枚举了2;即

    [2|b|c ]

    那么之后枚举到的数字就是 (200+x)

    如果 (200) - (300) 之间只有 (231)(230)(233) 满足条件,那么 (200) - (300) 之间的数的平方和就为

    [230^2+231^2+233^2 ]

    也就等于

    [(200+30)^2+(200+31)^2+(200+33)^2 ]

    展开后得到:

    [3 imes 200^2+2 imes 200 imes (30+31+33)+(30^2+31^2+3^32) ]

    并且我们可以据此得到状态转移了。

    (上述思路来自 Ender的博客 ,不过他的公式推到错了,多乘了一个3,所以还是看我的计算公式即可)

    实现的代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const long long MOD = 1000000007LL;
    struct Node {
        long long cnt;    // 数量
        long long sum;    // 和
        long long sum2;   // 平方和
        Node () {};
        Node (long long _cnt, long long _sum, long long _sum2) {
            cnt = _cnt; sum = _sum; sum2 = _sum2;
        }
    } f[22][7][7];
    int a[22];
    bool vis[22][7][7];
    long long pow10[22];
    void init() {
        memset(vis, 0, sizeof(vis));
        pow10[0] = 1;
        for (int i = 1; i < 22; i ++) pow10[i] = pow10[i-1] * 10 % MOD;
    }
    Node dfs(int pos, int pre, int ts, bool limit) {
        if (pos < 0) {
            int cnt = 1;
            if (pre == 0) cnt = 0;  // 不能被7整除
            if (ts == 0) cnt = 0;   // 所有数位的和不能被7整除
            return Node(cnt, 0, 0);
        }
        if (!limit && vis[pos][pre][ts]) return f[pos][pre][ts];
        int up = limit ? a[pos] : 9;
        Node res = Node(0, 0, 0);
        for (int i = 0; i <= up; i ++) {
            if (i == 7) continue;   // 不能包含7
            Node tmp = dfs(pos-1, (pre*10+i)%7, (ts+i)%7, limit && i==up);
            long long tmp_cnt = tmp.cnt;
            long long tmp_sum = tmp.sum;
            long long tmp_sum2 = tmp.sum2;
            long long t = pow10[pos] * i % MOD;
            long long now_sum = (t * tmp_cnt + tmp_sum) % MOD;
            long long now_sum2 = (tmp_cnt * t % MOD * t % MOD + 2LL * t % MOD * tmp_sum % MOD + tmp_sum2) % MOD;
            res.cnt = (res.cnt + tmp_cnt) % MOD;
            res.sum = (res.sum + now_sum) % MOD;
            res.sum2 = (res.sum2 + now_sum2) % MOD;
        }
        if (!limit && !vis[pos][pre][ts]) {
            vis[pos][pre][ts] = true;
            f[pos][pre][ts] = res;
        }
        return res;
    }
    long long get_num(long long x) {
        int pos = 0;
        while (x) {
            a[pos++] = x % 10;
            x /= 10;
        }
        return dfs(pos-1, 0, 0, true).sum2;
    }
    int T;
    long long L, R;
    int main() {
        init();
        scanf("%d", &T);
        while (T --) {
            scanf("%lld%lld", &L, &R);
            printf("%lld
    ", (get_num(R) - get_num(L-1) + MOD) % MOD);
        }
        return 0;
    }
    
  • 相关阅读:
    Qt画笔实现折线图
    Qt动态布局
    ffmpeg录制流媒体,正常方式停止录制
    解决libvlc_media_player_stop时死锁的方法
    Ubuntu 16 修改时区!
    qt窗口最小化之后无法打开
    Qt 之 去除窗口部件被选中后的焦点虚线框
    WINDOWS中, 如何查看一个运行中的程序是64位还是32位的
    DHTMLX学习总结
    mui plus.uploader.createUpload 上传文件服务端获取文件名中文乱码问题
  • 原文地址:https://www.cnblogs.com/quanjun/p/11976395.html
Copyright © 2020-2023  润新知