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;
}
时间: 2024-10-19 05:58:07

hdu-4507 吉哥系列故事——恨7不成妻 数位DP 状态转移分析/极限取模的相关文章

Hdu 4507 吉哥系列故事——恨7不成妻 (数位DP)

题目链接: Hdu 4507 吉哥系列故事——恨7不成妻 题目描述: 中文题面不描述. 解题思路: 从数据范围可看出是数位DP.根据题目给的限制,如果是求满足限制的数的数目的话,就很简单了.但是这个题目是让求满足题目中限制的数的平方和.我们可以求出区间中满足题目中限制的数的数目,和这些数的和,然后从这两个东西推出这些数的平方和. 假设现在我们已经递归出后面的x-1位满足题目限制的数的数目(num),和(sum),平方和(ssum),当前x位枚举为i,就可以推出当前节点改变为Num += num,

HDU 4507 吉哥系列故事――恨7不成妻(数位dp&amp;好魔性的一道好题)

题目链接:[kuangbin带你飞]专题十五 数位DP J - 吉哥系列故事――恨7不成妻 题意 Time Limit:500MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Description 单身! 依然单身! 吉哥依然单身! DS级码农吉哥依然单身! 所以,他生平最恨情人节,不管是214还是77,他都讨厌! 吉哥观察了214和77这两个数,发现: 2+1+4=7 7+7=7*2 77=7*11 最终,他发现原来这一切归根到底都是

hdu 4507 吉哥系列故事――恨7不成妻 数位dp

题意:中文题. 思路:设dp[pos][i][j]表示当前考虑pos位,之前的数位和对7的余数为i,之前的数值对7的余数为j,与之后的(pos+1)位组合满足条件 的状态(包括之后(pos+1)位满足的个数,后缀和sum,后缀平方和),详见代码: /********************************************************* file name: hdu4507.cpp author : kereo create time: 2015年02月10日 星期二

HDU ACM 4507 吉哥系列故事——恨7不成妻 -&gt;数位DP

题意:如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关-- 1.整数中某一位是7: 2.整数的每一位加起来的和是7的整数倍: 3.这个整数是7的整数倍: 现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和. 分析:数位DP,关键内容如下. (pre0+i)%7用于处理各个位数之和时候为7的倍数,(pre1*10+i)%7用于处理这个数是否为7的倍数. #include<iostream> using namespace std; const __int64 mod=100

HDU - 4507 吉哥系列故事――恨7不成妻 (数位DP)

Description 单身! 依然单身! 吉哥依然单身! DS级码农吉哥依然单身! 所以,他生平最恨情人节,不管是214还是77,他都讨厌! 吉哥观察了214和77这两个数,发现: 2+1+4=7 7+7=7*2 77=7*11 最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨厌一切和7有关的数! 什么样的数和7有关呢? 如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关―― 1.整数中某一位是7: 2.整数的每一位加起来的和是7的整数倍: 3.这个整数是7的整数

HDU 4507 —— 吉哥系列故事――恨7不成妻

吉哥系列故事――恨7不成妻 Time Limit:500MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 单身!  依然单身!  吉哥依然单身!  DS级码农吉哥依然单身!  所以,他生平最恨情人节,不管是214还是77,他都讨厌!    吉哥观察了214和77这两个数,发现:  2+1+4=7  7+7=7*2  77=7*11  最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨

HDU - 4507 - 吉哥系列故事——恨7不成妻(数位DP,数学)

链接: https://vjudge.net/problem/HDU-4507 题意: 单身! 依然单身! 吉哥依然单身! DS级码农吉哥依然单身! 所以,他生平最恨情人节,不管是214还是77,他都讨厌! 吉哥观察了214和77这两个数,发现: 2+1+4=7 7+7=72 77=711 最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨厌一切和7有关的数! 什么样的数和7有关呢? 如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关-- 1.整数中某一位是7: 2.

HDU 4507 吉哥系列故事――恨7不成妻(数位DP+结构体)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4507 题目大意:如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关 1.整数中某一位是7: 2.整数的每一位加起来的和是7的整数倍: 3.这个整数是7的整数倍: 求一定区间内和7无关的数字的平方和. 解题思路:这里我们用一个结构体分别存储符合条件的数的个数n,从当前位开始至末尾的数值s(比如一个数当前为1234***,*表示还不知道的位值,代表的就是***),从当前位开始至末尾的数的平方

HDU 4507 吉哥系列故事——恨7不成妻

需要推下平方和的式子..维护个数,和,平方和. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000007LL using namespace std; long long bit[30],tab[50],ret=0,t,l,r; struct pnt { long long val1,val2,val3; pnt (long