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

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

题目链接:https://cn.vjudge.net/contest/163023#problem/I
题目大意:
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关
  1、整数中某一位是7;
  2、整数的每一位加起来的和是7的整数倍;
  3、这个整数是7的整数倍;
 现在问题来了:吉哥想知道在一定区间内和7 无关 的数字的平方和。也就是三个条件都不满足呗。
题目分析:
这个题….
首先这三个条件都是基础数位dp,就不说了。
重点是怎么去求平方和。
需要维护三个值
1.符合条件数的个数 cnt
2.符合条件数的和 sum
3.符合条件数的平方和 sqr
为什么要维护这三个呢,接着往下看你就知道了
假定dfs推出返回的结构体是tmp,当前结果的结构体是ans
其中1是基础的数位dp很好维护;
2 tmp.sum * 10 + (10 ^ pos * i) * ans.cnt 就是上一步状态的和加上这一步加的
这一步加的就是10的当前位次方乘以i,因为有ans.cnt个嘛,所以再乘以ans.cnt
3 首先重新构建一下这个数 (10^pos * i + x)x是这个数的后面部分,就是上一次状态得到的那个数,则平方和就是(10^len*i)^2+x^2+2*10^len*i*x, 其中x^2=tmp.sqr;
ans.sqr += (2*10^pos*i*x)*tmp.cnt=(2*10^pos*i)*next.sum(神奇的化简)
ans.sqr += (10^pos*i)^2*tmp.cnt;

#include <bits/stdc++.h>

typedef long long ll;
const ll MOD = 1e9 + 7;
ll p[25];
ll data[20];

struct node
{
    ll cnt, sum, sqr;
    node(){cnt = -1; sum = sqr = 0;}
    node(ll cnt, ll sum, ll sqr) : cnt(cnt), sum(sum), sqr(sqr) {}
}dp[20][10][10];

node dfs(int pos, int sum1, int sum2, bool limit)
{
    if(pos == 0)
    {
        if(sum1 && sum2)
        {
            return node(1, 0, 0);
        }
        return node(0, 0, 0);
    }

    if(!limit && dp[pos][sum1][sum2].cnt != -1) return dp[pos][sum1][sum2];

    int up = limit ? data[pos] : 9;
    node ans;
    ans.cnt = 0;

    for(int i = 0; i <= up; i++)
    {
        if(i == 7) continue;

        node tmp = dfs(pos - 1, (i + sum1) % 7, (sum2 * 10 + i) % 7, i == up && limit);

        ans.cnt += tmp.cnt;
        ans.cnt %= MOD;

          ans.sum += (tmp.sum + ((p[pos] * i) % MOD) * tmp.cnt % MOD) % MOD;
          ans.sum %= MOD;
          ans.sqr += (tmp.sqr + (( 2 * p[pos] * i) % MOD) * tmp.sum) % MOD;
          ans.sqr %= MOD;
          ans.sqr += ((tmp.cnt * p[pos]) % MOD * p[pos] % MOD * i * i % MOD);
          ans.sqr %= MOD;
    }

    if(!limit) dp[pos][sum1][sum2] = ans;
    return ans;
}

ll solve(ll n)
{
    int pos = 0;
    while(n)
    {
        data[++pos] = n % 10;
        n /= 10;
    }

    node v = dfs(pos, 0, 0, true);
    return v.sqr;
}

int main()
{
    int t;
    scanf("%d", &t);
    p[1] = 1;
    for(int i = 2; i <= 20; i++) p[i] = (p[i - 1] * 10) % MOD;
    while(t--)
    {
        ll l, r;
        scanf("%lld %lld", &l, &r);
        ll ans = solve(r);
        ans -= solve(l - 1);
        printf("%lld\n",  (ans % MOD + MOD) % MOD);
    }
}

猜你喜欢

转载自blog.csdn.net/deerly_/article/details/79930085