HDOJ 4507 —— 數位DP

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

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


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
 

Source
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  4769 4768 4767 4766 4765 
 
挺明顯的數位DP,學習了kuangbin大神的寫法:http://www.cnblogs.com/kuangbin/archive/2013/05/01/3053233.html
思路是對應於題目的三個要求,我們去維護三個數:
1.與7無關的數                 
2.與7無關的數的和 --- 維護一個sum,每次加上p[pos] * i * 後面的數dfs
3.與7無關的數的平方和 ---維護一個sqsum,需要用到前面兩個
(pre*10^pos + next)^2= (pre*10^pos)^2+2*pre*10^pos*next +next^2
/*
ID: xinming2
PROG: stall4
LANG: C++
*/
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
///#define Online_Judge
#define outstars cout << "***********************" << endl;
#define clr(a,b) memset(a,b,sizeof(a))
#define lson l , mid  , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define mk make_pair
#define FOR(i , x , n) for(int i = (x) ; i < (n) ; i++)
#define FORR(i , x , n) for(int i = (x) ; i <= (n) ; i++)
#define REP(i , x , n) for(int i = (x) ; i > (n) ; i--)
#define REPP(i ,x , n) for(int i = (x) ; i >= (n) ; i--)
const int MAXN = 100000 + 50;
const int sigma_size = 26;
const long long LLMAX = 0x7fffffffffffffffLL;
const long long LLMIN = 0x8000000000000000LL;
const int INF = 0x7fffffff;
const int IMIN = 0x80000000;
#define eps 1e-8
const int mod = (int)1e9 + 7;
typedef long long LL;
const LL MOD = 1000000007LL;
const double PI = acos(-1.0);

typedef pair<int , int> pi;
#define Bug(s) cout << "s = " << s << endl;
///#pragma comment(linker, "/STACK:102400000,102400000")
struct Num
{
    LL cnt;///與7無關的個數
    LL sum;///與7無關的個數和
    LL sqsum;///平方和
}dp[20][20][20];///dp[i][j][k]表示處理的位數,數字和%7,數字%7
int digit[20];
LL p[20];///p[i] = 10^ i;
Num dfs(int pos , int pre1 , int pre2, bool fp)
{
    if(pos == -1)
    {
        Num tmp;
        tmp.cnt = (pre1 != 0) && (pre2 != 0);
        tmp.sum = tmp.sqsum = 0;
        return tmp;
    }
    if(!fp && dp[pos][pre1][pre2].cnt != -1)return dp[pos][pre1][pre2];
    int maxi = fp ? digit[pos] : 9;
    Num ans , tmp;
    ans.cnt = ans.sqsum = ans.sum = 0;
    for(int i = 0 ; i <= maxi ; i++)
    {
        if(i == 7)continue;
        tmp = dfs(pos - 1 , (pre1 + i) % 7 , (pre2 * 10 + i)% 7 , fp && i == maxi);
        ans.cnt += tmp.cnt;
        ans.cnt %= MOD;

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

        ans.sqsum += (tmp.sqsum + ((2 * p[pos] * i) % MOD) *tmp.sum) % MOD;///next^2 + 2*pre*10^pos*next
        ans.sqsum %= MOD;
        ans.sqsum += (tmp.cnt * p[pos]) % MOD * p[pos] % MOD * i * i % MOD;///(pre*10^pos)^2
        ans.sqsum %= MOD;
    }
    if(!fp)dp[pos][pre1][pre2] = ans;
    return ans;
}
LL f(LL n)
{
    int len = 0;
    while(n)
    {
        digit[len++] = n % 10;
        n /= 10;
    }
    return dfs(len - 1, 0 , 0 , 1).sqsum;
}
int main()
{
    int T;
    LL a , b;
    p[0] = 1;
    for(int i = 1 ; i < 20 ; i++)
    {
        p[i] = (p[i - 1] * 10) % MOD;
    }
    for(int i = 0 ; i < 20 ; i++)
    {
        for(int j = 0 ; j < 10 ; j++)
        {
            for(int k = 0 ; k < 10 ; k++)
            {
                dp[i][j][k].cnt = -1;
            }

        }
    }
    scanf("%d" , &T);
    while(T--)
    {
        scanf("%I64d%I64d" , &a , &b);
        LL ans = f(b) - f(a - 1);
        printf("%I64d\n" , (ans % MOD + MOD ) % MOD);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章