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

dp[i][mod1][mod2][0] 为 第i位后 数位和%7为mod1 数值%7为mod2 的满足条件的累加值的和
dp[i][mod1][mod2][1] 为 第i位后 数位和%7为mod1 数值%7为mod2 的满足条件的累加平方值的和
dp[i][mod1][mod2][2] 为 第i位后 数位和%7为mod1 数值%7为mod2 的满足条件的数量和
然后累加值 和 数量都是最普通的数位dp基本模型可以求出
平方和 的状态转移可以由 (a+b) ^ 2这个式子转移 既(a * ten[i]) ^ 2 * sum2 + sum1 + 2 * a * ten[i] * sum0 * sum2
注意取模

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define mod 1000000007ll
#define LL long long
using namespace std;
LL dp[31][11][11][3]; // 0 累加和 1 平方和 2 数量和
int sym[31][7][7];
LL x[100], l, ten[111];
void dfs(LL i, LL pre1, LL pre2, bool e, LL &sum1, LL &sum2, LL &sum3)
{
     if(i == -1)
     {
        if(pre1 % 7 != 0 && pre2 % 7 != 0) sum3 = 1;
        return ;
     }
     if(e && sym[i][pre1 % 7][pre2 % 7])
     {
          sum1 += dp[i][pre1 % 7][pre2 % 7][0];
          sum2 += dp[i][pre1 % 7][pre2 % 7][1];
          sum3 += dp[i][pre1 % 7][pre2 % 7][2];
          sum1 %= mod;
          sum2 %= mod;
          sum3 %= mod;
          return ;
     }
     int Max = e ? 9 : x[i];
     for(int j = 0; j <= Max; j++)
     {
         if(j != 7)
         {
          LL sum11 = 0;
          LL sum22 = 0;
          LL sum33 = 0;
          dfs(i - 1, pre1 + j, pre2 + ten[i] * j, !(!e && j == x[i]), sum11, sum22, sum33);
          sum3 += sum33;
          sum1 += sum11 + (sum33 % mod)* (j % mod) * (ten[i] % mod);
          sum2 += (j * (ten[i] % mod) * j % mod * (ten[i] % mod) % mod * (sum33 % mod) % mod + sum22 % mod + 2 * (ten[i] % mod) * j % mod * (sum11 % mod) % mod) % mod;
          sum1 %= mod;
          sum2 %= mod;
          sum3 %= mod;
         }
    }
     if(e)
     {
         sym[i][pre1 % 7][pre2 % 7] = 1;
         dp[i][pre1 % 7][pre2 % 7][0] = sum1;
         dp[i][pre1 % 7][pre2 % 7][1] = sum2;
         dp[i][pre1 % 7][pre2 % 7][2] = sum3;
         dp[i][pre1 % 7][pre2 % 7][0] %= mod;
         dp[i][pre1 % 7][pre2 % 7][1] %= mod;
         dp[i][pre1 % 7][pre2 % 7][2] %= mod;
     }
}
LL cal(LL n)
{
   l = 0;
   while(n)
   {
     x[l++] = n % 10;
     n /= 10;
   }
   LL ans1 = 0, ans2 = 0, ans3 = 0;
   dfs(l - 1, 0, 0, 0, ans1, ans2, ans3);
   return ans2;
}
int main()
{
    ten[0] = 1;
    for(int i = 1; i<= 20; i++) ten[i] = ten[i - 1] * 10;
    int t;
    scanf("%d", &t);
    while(t--)
    {
        LL a, b;
        scanf("%I64d %I64d", &a, &b);
        printf("%I64d\n", (cal(b) - cal(a - 1) + mod) % mod);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值