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

题目链接:吉哥系列故事——恨7不成妻。此题和HDU 3652 B-number这道题很相似,如果题解看不懂,可以先看3652这道题。

HDU 4507 吉哥系列故事——恨7不成妻 数位dp_第1张图片

代码如下:

#include 
#include 
#include 
#include 
#include 
#define mod1 (m+7-(j*(bit[i]%7))%7)%7
#define mod2 (n+7-j%7)%7

using namespace std;

typedef long long ll;
const ll mod = 1000000007;
ll dp1[20][10][2][7][7];  // 个数
ll dp2[20][10][2][7][7];  // 和
ll dp3[20][10][2][7][7];  // 平方和
ll bit[20];  // bit[i] = 10^(i - 1)
ll digit[20];
ll L, R;

void init()
{
    memset(dp1, 0, sizeof(dp1));
    memset(dp2, 0, sizeof(dp2));
    memset(dp3, 0, sizeof(dp3));
    memset(bit, 0, sizeof(bit));
    bit[1] = 1;
    for (int i = 2; i <= 19; i++)
        bit[i] = bit[i - 1] * 10;

    // 初始化位数为1的情况
    for (int i = 0; i <= 9; i++)
    {
        dp1[1][i][i == 7][i % 7][i % 7] = 1;
        dp2[1][i][i == 7][i % 7][i % 7] = i;
        dp3[1][i][i == 7][i % 7][i % 7] = i * i;
    }
    for (int i = 2; i <= 19; i++)
    for (int j = 0; j <= 9; j++)
    for (int k = 0; k <= 1; k++)
    for (int m = 0; m <= 6; m++)
    for (int n = 0; n <= 6; n++)
    for (int t = 0; t <= 9; t++)
    {
        if (!k && j == 7)
            continue;
        dp1[i][j][k][m][n]+=dp1[i-1][t][k][mod1][mod2];
        dp1[i][j][k][m][n]%=mod;
        dp2[i][j][k][m][n]+=dp2[i-1][t][k][mod1][mod2]+((j*(bit[i]%mod))%mod*dp1[i-1][t][k][mod1][mod2])%mod;
        dp2[i][j][k][m][n]%=mod;
        dp3[i][j][k][m][n]+=((((j*(bit[i]%mod))%mod)*((j*(bit[i]%mod))%mod))%mod*dp1[i-1][t][k][mod1][mod2])%mod
                            +((2*j*(bit[i]%mod))%mod*dp2[i-1][t][k][mod1][mod2])%mod+dp3[i - 1][t][k][mod1][mod2];
        dp3[i][j][k][m][n]%=mod;
        if (k && j == 7)
        {
            dp1[i][j][k][m][n]+=dp1[i-1][t][!k][mod1][mod2];
            dp1[i][j][k][m][n]%=mod;
            dp2[i][j][k][m][n]+=dp2[i-1][t][!k][mod1][mod2]+(((j*(bit[i]%mod))%mod)*dp1[i-1][t][!k][mod1][mod2])%mod;
            dp2[i][j][k][m][n]%=mod;
            dp3[i][j][k][m][n]+=((((j*(bit[i]%mod))%mod)*((j*(bit[i]%mod))%mod))%mod*dp1[i-1][t][!k][mod1][mod2])%mod
                                +((2*j*(bit[i]%mod))%mod*dp2[i-1][t][!k][mod1][mod2])%mod+dp3[i - 1][t][!k][mod1][mod2];
            dp3[i][j][k][m][n]%=mod;
        }
    }
}

ll cal(ll n)
{
    memset(digit, 0, sizeof(digit));
    int len = 0;
    while (n)
    {
        digit[++len] = n % 10;
        n /= 10;
    }
    ll ans = 0;
    ll num = 0;  // num为前缀模mod的值
    ll sum = 0, preffix = 0; // suffix为前缀模7的值,sum为前缀各位数字相加模7的值
    for (int i = len; i >= 1; i--)
    {
        for (int j = 0; j < digit[i]; j++)
        {
            if (j == 7)
                continue;
            int m1 = (7 - preffix % 7) % 7, m2 = (7 - sum % 7) % 7;
            for (int m = 0; m <= 6; m++)
                for (int n = 0; n <= 6; n++)
            {
                if (m != m1 && n != m2)
                {
                    ans += ((num*num)%mod*dp1[i][j][0][m][n])%mod+((2*num)%mod*dp2[i][j][0][m][n])%mod+dp3[i][j][0][m][n];
                    ans %= mod;
                }
            }
        }
        num += digit[i] * (bit[i] % mod);
        num %= mod;
        preffix += digit[i] * (bit[i] % 7);
        preffix %= 7;
        sum += digit[i];
        if (digit[i] == 7)
            break;
    }
    return ans;
}

int main()
{
    //freopen("test.txt", "r", stdin);

    int T;
    scanf("%d", &T);
    init();
    while (T--)
    {
        scanf("%I64d%I64d", &L, &R);
        printf("%I64d\n", (cal(R + 1) - cal(L) + mod) % mod);
    }
    return 0;
}




你可能感兴趣的:(ACM-数位dp)