zoukankan      html  css  js  c++  java
  • hdu-4507 吉哥系列故事——恨7不成妻 数位DP 状态转移分析/极限取模

    http://acm.hdu.edu.cn/showproblem.php?pid=4507

    求[L,R]中不满足任意条件的数的平方和mod 1e9+7。

    条件:

    1、整数中某一位是7;
    2、整数的每一位加起来的和是7的整数倍;
    3、这个整数是7的整数倍;

    首先想到数位DP,我们看下如何维护。

    最基本的dp需要两维来维护起始数字和长度,此外对于数位求和mod 7的余数需要一维来维护,对于一个数mod 7的余数需要一维维护。

    此外我们处理一下平方和,对于一个x开头,长度为len的xoo型数集,把它分成x*10^(len-1)+oo两部分,平方展开(x*10&(len-1))^2+2*(x*10^(len-1))*oo+oo^2,而我们要得到的是上式对于每一个oo的组合。

    第一项的系数应该是oo的种类数(即最基本的数位DP计数)。

    第二项的可以转化为2*(x*10^(len-1))*(oo1+oo2+...),即我们维护一下oo所有取值的和(维护方式类比维护平方)。

    第三项即oo^2的和,我们递归地维护一下。

    所以最后一维我们开[3]来维护基本数位计数,数值和,数值平方和。

    对于出现7的处理,会做数位DP都会处理。

    此题数据很接近long long max,请仔细取余(还得分%7 %1e9+7),不要偷懒~

    #include <iostream>
    #include <cstring>
    #include <string>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    #define LL long long
    using namespace std;
    const LL N = 1000015;
    const LL INF = 100000009;
    const LL mod = 1e9+7;
    const LL Len = 20;
    LL dp[Len][10][7][7][3];//bit,num,bitmod,valmod,sum(type: 0.cntSum 1.valSum 2.powSum
    LL bit[Len];
    LL bitMod7[Len];
    void init()
    {
        memset(dp, 0, sizeof dp);//初始化为0
        for (LL i = 0; i < 10; i++)
        {
            if (i == 7)continue;
            dp[0][i][i % 7][i % 7][0] = 1;
            dp[0][i][i % 7][i % 7][1] = i;
            dp[0][i][i % 7][i % 7][2] = i*i;
        }
        bit[0] = 1;
        bitMod7[0] = 1;
        for (LL i = 1; i < Len; i++)
        {
            bit[i] = bit[i - 1] * 10;
            bit[i] %= mod;
            bitMod7[i] = bitMod7[i - 1] * 10;
            bitMod7[i] %= 7;
        }
        for (LL len = 1; len < Len; len++)
        {
            for (LL i = 0; i < 10; i++)
            {
                if (i == 7)continue;
                for (LL m = 0; m < 7; m++)
                {
                    for (LL sm = 0; sm < 7; sm++)
                    {
                        LL aim = (m + i) % 7;//bitsum
                        LL aism = (sm + i*bitMod7[len]) % 7;//valsum
                        for (LL j = 0; j < 10; j++)
                        {
                            if (j == 7) continue;
                            dp[len][i][aim][aism][0] += dp[len - 1][j][m][sm][0];
                            dp[len][i][aim][aism][0] %= mod;
                            dp[len][i][aim][aism][1] += dp[len - 1][j][m][sm][1];
                            dp[len][i][aim][aism][1] %= mod;
                            dp[len][i][aim][aism][1] +=(((dp[len - 1][j][m][sm][0] * i) % mod)*bit[len]) % mod;
                            dp[len][i][aim][aism][1] %= mod;
                            dp[len][i][aim][aism][2] += dp[len - 1][j][m][sm][2];
                            dp[len][i][aim][aism][2] %= mod;
                            dp[len][i][aim][aism][2] += (((((dp[len - 1][j][m][sm][1] * 2) % mod)*i) % mod)*bit[len]) % mod;
                            dp[len][i][aim][aism][2] %= mod;
                            dp[len][i][aim][aism][2] += ((((((dp[len - 1][j][m][sm][0] * i) % mod*i) % mod)*bit[len]) % mod) * bit[len]) % mod;
                            dp[len][i][aim][aism][2] %= mod;
                        }
                    }
                }
            }
        }
    }
    LL arr[100];//当前求解的数的分解
    LL dfs(LL pos, LL preMod,LL presum,LL prebit)
    {
        if (pos == -1)return 0;//尾部
        LL num = arr[pos];//获取当前数
        LL cnt = 0;//计算以pre为前缀,后面从0~num-1开头的所有情况
        for (LL i = 0; i < num; i++)
        {
            if (i == 7)continue;
            for (LL m = 0; m < 7; m++)
            {
                if ((m + prebit)%7 == 0) continue;
                for (LL sm = 0; sm < 7; sm++)
                {
                    if ((presum + sm) % 7 == 0) continue;
                    //cout<<preMod<<' '<<dp[pos][i][m]
                    cnt += (((preMod*preMod) % mod)*dp[pos][i][m][sm][0])%mod;
                    cnt %= mod;
                    cnt += (((2 * preMod)%mod)*dp[pos][i][m][sm][1])%mod;
                    cnt %= mod;
                    cnt += dp[pos][i][m][sm][2];
                    cnt %= mod;
                }
            }    
        }
        if (num == 7)return cnt%mod;
        return (cnt + dfs(pos - 1, (preMod+num*bit[pos])%mod,(presum+num*bitMod7[pos])%7,(prebit+num)%7)%mod)%mod;//下一级dfs传递前缀(对于不同题目需要传递的前缀信息不同)
    }
    LL sol(LL x)
    {
        if (x == 0) return 0;
        x++;//dfs在求解时,只能解出x-1的所有情况,x需要在递归尾部特判,干脆我们将x++,这样正好求出x
        LL siz = 0;
        while (x)
            arr[siz++] = x % 10, x /= 10;
        LL ans = 0;
        ans = dfs(siz - 1,0,0,0);
        return ans;
    }
    int main() {
        cin.sync_with_stdio(false);
        LL n, m;
        init();
        int t;
        cin >> t;
        while (t--)
        {
            cin >> n >> m;
            cout << ((sol(m) - sol(n - 1))%mod+mod)%mod << endl;
        }
        return 0;
    }
  • 相关阅读:
    JS运动---运动基础(匀速运动)
    浅谈浏览器解析 URL+DNS 域名解析+TCP 三次握手与四次挥手+浏览器渲染页面
    浅谈JS重绘与回流
    浅谈JS函数节流及应用场景
    浅谈JS函数防抖及应用场景
    前端模块化(CommonJs,AMD和CMD)
    Git之SSH公钥与私钥
    vi/vim编辑器必知必会
    git笔录
    vue移动端弹框组件,vue-layer-mobile
  • 原文地址:https://www.cnblogs.com/LukeStepByStep/p/7492449.html
Copyright © 2011-2022 走看看