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;
}

 

posted @ 2017-09-07 23:17  Luke_Ye  阅读(323)  评论(0编辑  收藏  举报