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

Time Limit:500MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
 

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
 
1. 这道题是一道推公式的非常好的题目!
2. 这题要注意可能在计算过程中爆出了long long 的范围,要尽量优先计算不会超出范围的运算,否则就只能用大整数去计算了:)
举个栗子:
  下面代码中红色字体的计算式,如果把顺序换为
  base[len] * cur.num % MOD * i % MOD
就会WA,因为第一个乘法是两个long long级别的数,会溢出long long
具体分析,如下:


#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;

typedef long long LL;

struct P{
    LL num, sum, sqrt;
    P(LL a=-1, LL b=0, LL c=0):num(a),sum(b),sqrt(c){}
};

const int MOD = (int)1e9+7;
int a[20];
LL base[20];
P dp[20][7][7];


P dfs(int len, int mod1, int mod2, bool limit)
{
    if(len < 1)    
        return P(mod1 != 0 && mod2 != 0, 0, 0);
        
    if(!limit && dp[len][mod1][mod2].num!=-1)    return dp[len][mod1][mod2];
    int maxn = limit ? a[len] : 9;
    P ret(0,0,0);
    for(int i=0; i<=maxn; i++) {
        if(i==7)    continue;
        P cur = dfs(len-1, (mod1+i%7)%7, (mod2*(10%7)+i)%7, limit&&i==maxn);
        ret.num = (ret.num + cur.num) % MOD;
        ret.sum = (ret.sum + cur.sum + i * base[len] % MOD * cur.num % MOD) % MOD;
        LL temp = i*base[len]%MOD;
        ret.sqrt = (ret.sqrt + cur.sqrt + cur.num*temp%MOD*temp%MOD + 2*temp%MOD*cur.sum%MOD)%MOD;
    }
    if(!limit)    dp[len][mod1][mod2] = ret;
    return ret;
}

LL f(LL x)
{
    int len = 0;
    while(x) {
        a[++len] = x%10;
        x /= 10;
    }
    return dfs(len, 0, 0, 1).sqrt;
}

void Init()
{
    base[1]=1;
    for(int i=2; i<20; i++) {
        base[i] = base[i-1]*10;
//        printf("%lld\n", base[i]); //
    }    
}

int main ()
{
    Init();
    
    int T;
    LL l, r;
    scanf("%d", &T);
    while(T--) {
        scanf("%I64d%I64d", &l, &r);
        printf("%I64d\n", (f(r) - f(l-1) + MOD) % MOD);
    }
    
    return 0;
}

 

posted on 2016-04-14 22:27  SuperChan  阅读(204)  评论(0编辑  收藏  举报

导航