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

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

Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 2532    Accepted Submission(s): 747


Problem 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的整数倍;

  现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。
 

Input
输入数据的第一行是case数T(1 <= T <= 50),然后接下来的T行表示T个case;每个case在一行内包含两个正整数L, R(1 <= L <= R <= 10^18)。
 

Output
请计算[L,R]中和7无关的数字的平方和,并将结果对10^9 + 7 求模后输出。
 

Sample Input
  
  
3 1 9 10 11 17 17
 

Sample Output
  
  
236 221 0
 

思路:数位dp。

设后i-1位合法的数字有N个,num1, num2, num3, num4...numN考虑第i位的x,则num = 10^(i-1) * x。

和为num * N +(num1 + ... + numN)。

平方和为(num + num1)^2 + (num + num2) ^ 2 + (num + num3) ^ 2 + ... + (num + numN) ^ 2。   

化简后 = N * num^2 + 2 * num * (num1+...+numN) + (num1^2 + ... + numN^2)。

用dp维护个数cnt,和sum1, 平方和sum2即可。


AC代码:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 1000000
#define eps 1e-8
#define MAXN (200000+10)
#define MAXM (100000+10)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while((a)--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
#pragma comment(linker, "/STACK:102400000,102400000")
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii;
struct Node{
    LL cnt, sum1, sum2;
};
Node dp[30][7][7];
int bit[30];
LL P[30];
void Init()
{
    CLR(dp, -1);
    P[0] = 1LL;
    for(int i = 1; i < 30; i++)
        P[i] = P[i-1] * 10 % MOD;
}
void add(LL &x, LL y)
{
    x += y;
    x %= MOD;
}
LL Fac(LL x){
    return x * x % MOD;
}
Node DFS(int pos, int presum, int preyu, bool yes)
{
    if(pos == -1)
    {
        Node temp; temp.cnt = (presum && preyu);
        temp.sum1 = temp.sum2 = 0LL;
        return temp;
    }
    if(!yes && dp[pos][presum][preyu].cnt != -1) return dp[pos][presum][preyu];
    Node ans, temp; ans.cnt = ans.sum1 = ans.sum2 = 0LL;
    int End = yes ? bit[pos] : 9;
    for(int i = 0; i <= End; i++)
    {
        if(i == 7) continue;
        temp = DFS(pos-1, (presum+i)%7, (preyu*10+i)%7, yes&&i==End);
        add(ans.cnt, temp.cnt);
        add(ans.sum1, (temp.sum1 + temp.cnt * P[pos] % MOD * i % MOD) % MOD);
        add(ans.sum2, ((temp.cnt * Fac(P[pos]) % MOD * Fac(i) % MOD + temp.sum2) % MOD + temp.sum1 * 2 % MOD * P[pos] % MOD * i % MOD) % MOD);
    }
    if(!yes) dp[pos][presum][preyu] = ans;
    return ans;
}
LL Count(LL n)
{
    int len = 0;
    while(n)
    {
        bit[len++] = n % 10;
        n /= 10;
    }
    return DFS(len-1, 0, 0, 1).sum2;
}
int main()
{
    Init();
    int t; Ri(t);
    W(t)
    {
        LL n, m; Rl(n); Rl(m);
        Pl(((Count(m) - Count(n-1)) % MOD + MOD) % MOD);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值