[一本通提高数位动态规划]恨7不成妻--题解--胎教级教学
- 1前言
- 2问题
- 3化繁为简--对于方案数的求解
- (1)子问题的分解
- (2)数位dp-part1状态设置--利用约束条件推状态
- (3)数位dp-part2状态转移
- (4)数位dp-part3利用状态求解问题
- (5)方案数求解的代码
 
 
- 4问题转化--平方和的加入
- (1)状态转移--问题的变化
- (2)改进算法--从状态出发
- (3)利用新状态--问题再求解
- (4)问题的终结--附上代码
 
 
- 5后记
 
1前言
一本通提高篇的毒瘤数位dp终于要结束了
 然而…我遇到了这道毒中之毒
 网上的题解都是依托构思,我猜他们都是抄的代码
 我要是抄代码用你发?
 甚至有人直接抄袭acwing yxc老师的图片
 几十篇题解凑不出完整的思路,你家题解是散装的
 所有人都在劝你抄代码,只有我在写胎教级教学
 本文的所有思路均有证明,终结你关于这道毒瘤题的一切疑问
 所有公式均使用 
     
      
       
       
         L 
        
       
         a 
        
       
         t 
        
       
         e 
        
       
         x 
        
       
      
        Latex 
       
      
    Latex,包清晰
 本题的难度较高,新手不要轻易尝试
 建议先阅读
 论数位dp–胎教级教学
 B3883 [信息与未来 2015] 求回文数 数位dp题解
 论进制类型的数位dp:胎教级教学
 [一本通提高数位动态规划]数字游戏:取模数题解
2问题
如图
 
 注意!要求的是平方和,这是本题最大的毒瘤点
 (出题人yyds (永远单身) )
 而且,先放下平方和不看,本题对于合法数的约束条件有整整 
     
      
       
       
         3 
        
       
      
        3 
       
      
    3个
 面对复杂的问题,我们可以使用dp式解题法
 先求解子问题,再转移
 我们一步一步地解决吧
3化繁为简–对于方案数的求解
(1)子问题的分解
我们发现,求解平方和的性质是如此毒瘤,以至于扰乱了整个dp过程
 一步到正解过于困难,我们可以抛开这个条件,先考虑求解合法方案数
(2)数位dp-part1状态设置–利用约束条件推状态
dp的状态设置要满足两个条件
 1.构成子问题,即和最终要求解的问题有一致性
 2.可转移性,可以利用已经求出的状态来推新的状态
 首先,对于子问题,我们转化原问题的约束条件
 设一个合法方案的数值为 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x, 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x的第 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i位为 
     
      
       
        
        
          x 
         
        
          i 
         
        
       
      
        x_{i} 
       
      
    xi,则有
  
      
       
        
        
          { 
         
         
          
           
            
             
             
               ∀ 
              
              
              
                x 
               
              
                i 
               
              
             
               , 
              
              
              
                x 
               
              
                i 
               
              
             
               ≠ 
              
             
               7 
              
             
            
           
          
          
           
            
             
             
               ∑ 
              
              
              
                x 
               
              
                i 
               
              
             
               m 
              
             
               o 
              
             
               d 
              
             
               7 
              
             
               ≠ 
              
             
               0 
              
             
            
           
          
          
           
            
             
             
               x 
              
             
               m 
              
             
               o 
              
             
               d 
              
             
               7 
              
             
               ≠ 
              
             
               0 
              
             
            
           
          
         
        
       
         \left \{ \begin{array}{c} \forall x_{i},x_{i}\ne7\\ \sum x_{i} mod 7 \ne 0\\ x mod 7 \ne 0 \end{array} \right. 
        
       
     ⎩ 
              ⎨ 
              ⎧∀xi,xi=7∑ximod7=0xmod7=0
 这三个条件互相不干扰,我们为 
     
      
       
       
         d 
        
       
         p 
        
       
      
        dp 
       
      
    dp数组增加三个维度
 1. 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x的最高位
 2. 
     
      
       
       
         ∑ 
        
        
        
          x 
         
        
          i 
         
        
       
         m 
        
       
         o 
        
       
         d 
        
       
         7 
        
       
      
        \sum x_{i} mod 7 
       
      
    ∑ximod7的值
 3. 
     
      
       
       
         x 
        
       
         m 
        
       
         o 
        
       
         d 
        
       
         7 
        
       
      
        x mod 7 
       
      
    xmod7的值
 然后,考虑可转移性
 可以发现,我们在 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x前面插入一位数 
     
      
       
       
         k 
        
       
      
        k 
       
      
    k,设 
     
      
       
       
         k 
        
       
      
        k 
       
      
    k为第 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i位数,新的状态可以由之前的转移过来,(因为状态合法和不合法都要处理,为了体现可转移性,我们假定当前状态是合法的)
 对于维度1,直接枚举可能的最高位(当然不能为 
     
      
       
       
         7 
        
       
      
        7 
       
      
    7)
 对于维度2,取 
     
      
       
       
         ( 
        
       
         7 
        
       
         − 
        
       
         k 
        
       
         ) 
        
       
         m 
        
       
         o 
        
       
         d 
        
       
         7 
        
       
      
        (7-k) mod 7 
       
      
    (7−k)mod7(温馨提示:在合法的情况下为 
     
      
       
       
         7 
        
       
         − 
        
       
         k 
        
       
      
        7-k 
       
      
    7−k,因为各位和模 
     
      
       
       
         7 
        
       
      
        7 
       
      
    7为 
     
      
       
       
         0 
        
       
      
        0 
       
      
    0)
 对于维度3,取 
     
      
       
       
         ( 
        
       
         7 
        
       
         − 
        
       
         k 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         ) 
        
       
      
        (7-k \times 10^{i}) 
       
      
    (7−k×10i)
 这种转移方式可以采用,但是因为要枚举当前位数 
     
      
       
       
         − 
        
       
         1 
        
       
      
        -1 
       
      
    −1的情况
 我们还要再开一维,为当前的位数
 所以状态得出
  
     
      
       
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           , 
          
         
           j 
          
         
           , 
          
         
           k 
          
         
           , 
          
         
           l 
          
         
        
       
      
        dp_{i,j,k,l} 
       
      
    dpi,j,k,l为 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i位, 
     
      
       
       
         j 
        
       
      
        j 
       
      
    j开头,数值模 
     
      
       
       
         7 
        
       
      
        7 
       
      
    7为 
     
      
       
       
         k 
        
       
      
        k 
       
      
    k,各为之和模 
     
      
       
       
         7 
        
       
      
        7 
       
      
    7为 
     
      
       
       
         l 
        
       
      
        l 
       
      
    l的方案个数
(3)数位dp-part2状态转移
其实状态转移的方法,我们已经在设置状态的时候考虑好了
 枚举 
     
      
       
       
         i 
        
       
         , 
        
       
         j 
        
       
         , 
        
       
         k 
        
       
         , 
        
       
         l 
        
       
      
        i,j,k,l 
       
      
    i,j,k,l,即 
     
      
       
       
         d 
        
       
         p 
        
       
      
        dp 
       
      
    dp的所有维度,此外,还需枚举一个 
     
      
       
       
         h 
        
       
      
        h 
       
      
    h,代表前一位的情况
 得状态转移方程:(这里有点绕,慢慢理解即可)
  
     
      
       
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           , 
          
         
           j 
          
         
           , 
          
         
           k 
          
         
           , 
          
         
           l 
          
         
        
       
         = 
        
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           , 
          
         
           j 
          
         
           , 
          
         
           k 
          
         
           , 
          
         
           l 
          
         
        
       
         + 
        
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           − 
          
         
           1 
          
         
           , 
          
         
           h 
          
         
           , 
          
         
           m 
          
         
           o 
          
         
           d 
          
         
           ( 
          
         
           k 
          
         
           − 
          
         
           ( 
          
         
           1 
          
          
          
            0 
           
          
            i 
           
          
         
           × 
          
         
           j 
          
         
           ) 
          
         
           ) 
          
         
           , 
          
         
           m 
          
         
           o 
          
         
           d 
          
         
           ( 
          
         
           l 
          
         
           − 
          
         
           j 
          
         
           ) 
          
         
        
       
      
        dp_{i,j,k,l} = dp_{i,j,k,l}+dp_{i-1,h,mod(k-(10^i \times j)),mod(l-j)} 
       
      
    dpi,j,k,l=dpi,j,k,l+dpi−1,h,mod(k−(10i×j)),mod(l−j)
 其中 
     
      
       
       
         m 
        
       
         o 
        
       
         d 
        
       
         ( 
        
       
         x 
        
       
         ) 
        
       
      
        mod(x) 
       
      
    mod(x)代表数 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x模 
     
      
       
       
         7 
        
       
      
        7 
       
      
    7取正数
 逆天状态转移方程
 我们再来一遍,一维一维看
 维度 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i:上一位当然为 
     
      
       
       
         i 
        
       
         − 
        
       
         1 
        
       
      
        i-1 
       
      
    i−1
 维度 
     
      
       
       
         j 
        
       
      
        j 
       
      
    j:枚举的 
     
      
       
       
         h 
        
       
      
        h 
       
      
    h
 维度 
     
      
       
       
         k 
        
       
      
        k 
       
      
    k: 
     
      
       
       
         j 
        
       
      
        j 
       
      
    j所在第 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i位,值增加了 
     
      
       
       
         j 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
      
        j \times 10^i 
       
      
    j×10i变成 
     
      
       
       
         k 
        
       
      
        k 
       
      
    k,得这一维为 
     
      
       
       
         m 
        
       
         o 
        
       
         d 
        
       
         ( 
        
       
         k 
        
       
         − 
        
       
         ( 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         × 
        
       
         j 
        
       
         ) 
        
       
         ) 
        
       
      
        mod(k-(10^i \times j)) 
       
      
    mod(k−(10i×j))
 维度 
     
      
       
       
         l 
        
       
      
        l 
       
      
    l:加上一位 
     
      
       
       
         j 
        
       
      
        j 
       
      
    j,各位之和变为 
     
      
       
       
         l 
        
       
      
        l 
       
      
    l ,得 
     
      
       
       
         m 
        
       
         o 
        
       
         d 
        
       
         ( 
        
       
         l 
        
       
         − 
        
       
         j 
        
       
         ) 
        
       
      
        mod(l-j) 
       
      
    mod(l−j)
 (觉得状态转移方程太复杂不可读,拆开看好一些QwQ)
 看到这了,就该代码出场了
 附初始化部分的代码(c++)
const long long MOD = 1e9+7; 
long long dp[20][20][10][10];//状态 
long long e[20];//预处理10的幂 
long long mmod(long long x){//模7防负数 
	return(x%7+7)%7;
}
long long n,a,b;
void init(){
	e[0] = 1;//10^0
	for(long long i = 0;i<=9;i++){//预处理个位数 
		dp[1][i][i%7][i%7] = 1-(i==7);
	}
	for(long long i = 1;i<=20;i++){
		e[i] = e[i-1]*10;
		e[i]%=7;
		for(long long j = 0;j<=9;j++){
			if(j==7){//判断7 
				continue;
			}
			for(long long k = 0;k<7;k++){
				for(long long l = 0;l<7;l++){
					for(long long h = 0;h<=9;h++){
						if(h!=7){//判断7 
							dp[i][j][k][l]+=dp[i-1][h][mmod(k-(j*e[i]))][mmod(l-j)];//状态转移方程的体现 
							dp[i][j][k][l]%=MOD;
						}
					}
				}
			}
		}
	}
}
(4)数位dp-part3利用状态求解问题
我们依旧先划分问题,举例数 
     
      
       
       
         23456 
        
       
      
        23456 
       
      
    23456
 可划分为 
     
      
       
       
         1 
        
       
         − 
        
       
         19999 
        
       
      
        1-19999 
       
      
    1−19999和 
     
      
       
       
         20000 
        
       
         − 
        
       
         23456 
        
       
      
        20000-23456 
       
      
    20000−23456
 首先考虑 
     
      
       
       
         1 
        
       
         − 
        
       
         19999 
        
       
      
        1-19999 
       
      
    1−19999区间,对于 
     
      
       
       
         i 
        
       
      
        i 
       
      
    i位(此处 
     
      
       
       
         i 
        
       
         = 
        
       
         5 
        
       
      
        i = 5 
       
      
    i=5),枚举 
     
      
       
       
         0 
        
       
         ≤ 
        
       
         j 
        
       
         ≤ 
        
       
         9 
        
       
         , 
        
       
         j 
        
       
         ≠ 
        
       
         7 
        
       
      
        0 \le j \le 9,j \ne 7 
       
      
    0≤j≤9,j=7
 答案加上 
     
      
       
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           , 
          
         
           j 
          
         
           , 
          
         
           k 
          
         
           , 
          
         
           l 
          
         
        
       
      
        dp_{i,j,k,l} 
       
      
    dpi,j,k,l即可,这里 
     
      
       
       
         k 
        
       
         , 
        
       
         l 
        
       
      
        k,l 
       
      
    k,l都是合法的
 那怎么判断合法呢,分别处理前面的数值和各位和,就可以用来判断了
 我们在写代码时可以用函数将这一步独立出来
 至于 
     
      
       
       
         20000 
        
       
         − 
        
       
         23456 
        
       
      
        20000-23456 
       
      
    20000−23456这个区间,向后递推处理即可,边界问题要特判,其他就没什么难的了
(5)方案数求解的代码
代码如下,记得模上 
     
      
       
       
         1 
        
        
        
          0 
         
        
          9 
         
        
       
         + 
        
       
         7 
        
       
      
        10^9+7 
       
      
    109+7,记得开 
     
      
       
       
         l 
        
       
         o 
        
       
         n 
        
       
         g 
        
       
         l 
        
       
         o 
        
       
         n 
        
       
         g 
        
       
      
        long long 
       
      
    longlong
 (作者因为没调用初始化函数调了半天)
#include<bits/stdc++.h>
using namespace std;
const long long MOD = 1e9+7; 
long long dp[30][20][10][10];//状态 
long long e[20];//预处理10的幂 
long long mmod(long long x){//模7防负数 
	return(x%7+7)%7;
}
long long n,a,b;
void init(){
	e[0] = 1;//10^0
	for(long long i = 0;i<=9;i++){//预处理个位数 
		dp[1][i][i%7][i%7] = 1-(i==7);
	}
	for(long long i = 1;i<=20;i++){
		e[i] = e[i-1]*10;
		e[i]%=7;
		for(long long j = 0;j<=9;j++){
			if(j==7){//判断7 
				continue;
			}
			for(long long k = 0;k<7;k++){
				for(long long l = 0;l<7;l++){
					for(long long h = 0;h<=9;h++){
						if(h!=7){//判断7 
							dp[i][j][k][l]+=dp[i-1][h][mmod(k-(j*e[i]))][mmod(l-j)];//状态转移方程的体现 
							dp[i][j][k][l]%=MOD;
						}
					}
				}
			}
		}
	}
}
long long get(long long i1,long long j1,long long k1,long long l1){
	long long ans = 0;
	for(int k = 0;k<7;k++){
		for(int l = 0;l<7;l++){
			if(k!=k1&&l!=l1){
				ans+=dp[i1][j1][k][l];
			}
		}
	}
	return ans;
}
long long solve(long long x){
	if(x==0){
		return 0;
	}
	long long h = x,s[1145],idx = 0,ans = 0,tmp1 = 0,tmp2 = 0;
	while(h){
		s[++idx] = h%10;
		h/=10; 
	}
	for(int i = idx;i>=1;i--){
		for(int j = 0;j<s[i];j++){
			if(j==7){
				continue;
			}
			long long k1 = mmod(-tmp1*e[i]),l1 = mmod(-tmp2);
			ans+=get(i,j,k1,l1);
		}
		if(s[i]==7){
			break;
		}
		tmp1 = tmp1*10+s[i];
		tmp2 = tmp2+s[i];
		if(i==1&&tmp1%7!=0&&tmp2%7!=0){
			ans++;
		}
	}
	return ans;
} 
int main(){
	init();
	cin>>n;
	while(n--){
		cin>>a>>b;
		long long ans = solve(b)-solve(a-1);
		cout<<ans<<endl;
	}
	return 0;
}
4问题转化–平方和的加入
(1)状态转移–问题的变化
我们的dp式解题法已经求好了状态,接下来该进行转移了
 平方和…这个问题会破坏掉我们的整个求解过程
 所以我们要尝试在原来求解方式的基础上改进,就要利用好平方和的性质
(2)改进算法–从状态出发
首先,要具有子问题的性质,我们不可能处理出所有符合条件的数,再开一个数组麻烦,那就开一个结构体
 使原有的 
     
      
       
       
         d 
        
       
         p 
        
       
      
        dp 
       
      
    dp数组不止存方案数,还存储所有合法数的平方和
 对于 
     
      
       
       
         d 
        
        
        
          p 
         
         
         
           i 
          
         
           , 
          
         
           j 
          
         
           , 
          
         
           k 
          
         
           , 
          
         
           l 
          
         
        
       
      
        dp_{i,j,k,l} 
       
      
    dpi,j,k,l,在 
     
      
       
       
         i 
        
       
         = 
        
       
         1 
        
       
      
        i=1 
       
      
    i=1的条件下显然可以直接求出平方和(就一种方案)
 还记得我们求方案数时状态转移的原理吗
 在原有的数前面加上一位,那么我们设原数为 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x,新的一位为 
     
      
       
       
         h 
        
       
      
        h 
       
      
    h
 则新的数为 
     
      
       
       
         h 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         + 
        
       
         x 
        
       
      
        h \times 10^{i}+x 
       
      
    h×10i+x,表示为平方 
     
      
       
       
         ( 
        
       
         h 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         + 
        
       
         x 
        
        
        
          ) 
         
        
          2 
         
        
       
      
        (h \times 10^{i}+x)^2 
       
      
    (h×10i+x)2
 根据完全平方公式得原式等价于
  
     
      
       
       
         ( 
        
       
         h 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
        
        
          ) 
         
        
          2 
         
        
       
         + 
        
       
         2 
        
       
         × 
        
       
         ( 
        
       
         h 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         ) 
        
       
         × 
        
       
         x 
        
       
         + 
        
        
        
          x 
         
        
          2 
         
        
       
      
        (h \times 10^i)^2+2\times(h \times 10^i) \times x+x^2 
       
      
    (h×10i)2+2×(h×10i)×x+x2
 进一步化简:
  
     
      
       
        
        
          h 
         
        
          2 
         
        
       
         × 
        
       
         1 
        
        
        
          0 
         
         
         
           2 
          
         
           i 
          
         
        
       
         + 
        
       
         2 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         h 
        
       
         x 
        
       
         + 
        
        
        
          x 
         
        
          2 
         
        
       
      
        h^2\times10^{2i} + 2\times 10^ihx + x^2 
       
      
    h2×102i+2×10ihx+x2
 我们发现了一个极好的性质!!!, 
     
      
       
        
        
          x 
         
        
          2 
         
        
       
      
        x^2 
       
      
    x2,这正是子问题
 对于每一个新的数,我们都套用公式
 设原来 
     
      
       
       
         n 
        
       
      
        n 
       
      
    n个 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x的平方和为 
     
      
       
       
         s 
        
       
         u 
        
        
        
          m 
         
        
          x 
         
        
       
      
        sum_{x} 
       
      
    sumx,新数 
     
      
       
       
         y 
        
       
      
        y 
       
      
    y的平方和为 
     
      
       
       
         s 
        
       
         u 
        
        
        
          m 
         
        
          y 
         
        
       
      
        sum_{y} 
       
      
    sumy,则有
  
     
      
       
       
         s 
        
       
         u 
        
        
        
          m 
         
        
          y 
         
        
       
         = 
        
       
         n 
        
       
         × 
        
        
        
          h 
         
        
          2 
         
        
       
         × 
        
       
         1 
        
        
        
          0 
         
         
         
           2 
          
         
           i 
          
         
        
       
         + 
        
       
         2 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         h 
        
       
         ( 
        
        
        
          x 
         
        
          1 
         
        
       
         + 
        
        
        
          x 
         
        
          2 
         
        
       
         . 
        
       
         . 
        
       
         . 
        
       
         . 
        
       
         . 
        
       
         . 
        
       
         + 
        
        
        
          x 
         
        
          n 
         
        
       
         ) 
        
       
         + 
        
       
         s 
        
       
         u 
        
        
        
          m 
         
        
          x 
         
        
       
      
        sum_{y} = n \times h^2 \times 10^{2i}+2 \times 10^ih(x_1+x_2......+x_n)+sum_{x} 
       
      
    sumy=n×h2×102i+2×10ih(x1+x2......+xn)+sumx
 原来的方案数和平方和都用上了,好啊, 
     
      
       
       
         10 
        
       
      
        10 
       
      
    10的幂照常预处理
 但是呢,意外出现了, 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x的求和我们没存过
 那还想啥了,存呗
 想想转移(以下所有设的未知数的意思和上文相同)
 每个新数 
     
      
       
       
         y 
        
       
         = 
        
       
         h 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         + 
        
       
         x 
        
       
      
        y = h \times 10^i+x 
       
      
    y=h×10i+x
 则 
     
      
       
       
         ∑ 
        
       
         y 
        
       
         = 
        
       
         ∑ 
        
       
         x 
        
       
         + 
        
       
         n 
        
       
         × 
        
       
         h 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
      
        \sum y = \sum x+n\times h \times10^i 
       
      
    ∑y=∑x+n×h×10i
 归纳以上内容,得状态转移方程(枚举的上一位依旧设为 
     
      
       
       
         h 
        
       
      
        h 
       
      
    h)
 (此处为了清晰不用 
     
      
       
       
         d 
        
       
         p 
        
       
      
        dp 
       
      
    dp的结构体表示形式, 
     
      
       
       
         c 
        
       
         n 
        
       
         t 
        
       
      
        cnt 
       
      
    cnt代指方案数, 
     
      
       
       
         s 
        
       
         u 
        
       
         m 
        
       
      
        sum 
       
      
    sum代指求和, 
     
      
       
       
         r 
        
       
         e 
        
       
         s 
        
       
      
        res 
       
      
    res代指平方和,如果觉得太复杂不可读也可以先看看后面的代码部分)
 (为了更加清晰可读,前一个状态的 
     
      
       
       
         k 
        
       
         , 
        
       
         l 
        
       
      
        k,l 
       
      
    k,l,即 
     
      
       
       
         m 
        
       
         o 
        
       
         d 
        
       
         ( 
        
       
         k 
        
       
         − 
        
       
         ( 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         × 
        
       
         j 
        
       
         ) 
        
       
         ) 
        
       
         , 
        
       
         m 
        
       
         o 
        
       
         d 
        
       
         ( 
        
       
         l 
        
       
         − 
        
       
         j 
        
       
         ) 
        
       
      
        mod(k-(10^i \times j)),mod(l-j) 
       
      
    mod(k−(10i×j)),mod(l−j)统一替换为 
     
      
       
       
         u 
        
       
         , 
        
       
         v 
        
       
      
        u,v 
       
      
    u,v)
 (所有上一个状态的下标都统一表示为 
     
      
       
       
         s 
        
       
         2 
        
       
      
        s2 
       
      
    s2,当前状态表示为 
     
      
       
       
         s 
        
       
         1 
        
       
      
        s1 
       
      
    s1)
 (公式不代表代码,取模部分这里不体现代码里会有的)
  
     
      
       
       
         c 
        
       
         n 
        
        
        
          t 
         
         
         
           s 
          
         
           1 
          
         
        
       
         = 
        
       
         c 
        
       
         n 
        
        
        
          t 
         
         
         
           s 
          
         
           1 
          
         
        
       
         + 
        
       
         c 
        
       
         n 
        
        
        
          t 
         
         
         
           s 
          
         
           2 
          
         
        
       
      
        cnt_{s1} = cnt_{s1}+cnt_{s2} 
       
      
    cnts1=cnts1+cnts2
  
     
      
       
       
         s 
        
       
         u 
        
        
        
          m 
         
         
         
           s 
          
         
           1 
          
         
        
       
         = 
        
       
         s 
        
       
         u 
        
        
        
          m 
         
         
         
           s 
          
         
           1 
          
         
        
       
         + 
        
       
         s 
        
       
         u 
        
        
        
          m 
         
         
         
           s 
          
         
           2 
          
         
        
       
         + 
        
       
         c 
        
       
         n 
        
        
        
          t 
         
         
         
           s 
          
         
           2 
          
         
        
       
         × 
        
       
         j 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
      
        sum_{s1} = sum_{s1}+sum_{s2}+cnt_{s2}\times j \times 10^i 
       
      
    sums1=sums1+sums2+cnts2×j×10i
  
     
      
       
       
         r 
        
       
         e 
        
        
        
          s 
         
         
         
           s 
          
         
           1 
          
         
        
       
         = 
        
       
         r 
        
       
         e 
        
        
        
          s 
         
         
         
           s 
          
         
           1 
          
         
        
       
         + 
        
       
         c 
        
       
         n 
        
        
        
          t 
         
         
         
           s 
          
         
           2 
          
         
        
       
         × 
        
        
        
          j 
         
        
          2 
         
        
       
         × 
        
       
         1 
        
        
        
          0 
         
         
         
           2 
          
         
           i 
          
         
        
       
         + 
        
       
         2 
        
       
         × 
        
       
         1 
        
        
        
          0 
         
        
          i 
         
        
       
         j 
        
       
         x 
        
       
         × 
        
       
         s 
        
       
         u 
        
        
        
          m 
         
         
         
           s 
          
         
           2 
          
         
        
       
         + 
        
       
         r 
        
       
         e 
        
        
        
          s 
         
         
         
           s 
          
         
           2 
          
         
        
       
      
        res_{s1} = res_{s1}+cnt_{s2}\times j^2 \times 10^{2i}+2\times 10^ijx\times sum_{s2}+res_{s2} 
       
      
    ress1=ress1+cnts2×j2×102i+2×10ijx×sums2+ress2
 初始化这边的代码也一并附上,注意循环最里层的写法,直接利用指针把原 
     
      
       
       
         d 
        
       
         p 
        
       
      
        dp 
       
      
    dp数组的值带入到 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x里,多使用这些技巧可以改善码风
 附初始化代码(c++)
const long long MOD = 1e9+7; 
long long e[20],g[20];//预处理10的幂
struct node{
	long long cnt,sum,res;
}dp[30][20][10][10];//状态 
long long mmod(long long x){//模7防负数 
	return (x%7+7)%7;
}
long long mmmod(long long x){//模1e9+7防负数
	return (x%MOD+MOD)%MOD;
}
long long n,a,b;
void init(){
	e[0] = 1;//10^0
	g[0] = 1;
	for(long long i = 0;i<=9;i++){//预处理个位数 
		if(i==7){
			continue;
		}
		node &u = dp[1][i][i%7][i%7];
		u.cnt++;
		u.sum+=i;
		u.res+=i*i;
	}
	for(long long i = 1;i<=20;i++){
		e[i] = e[i-1]*10;
		e[i]%=7;
		g[i] = g[i-1]*10;
		g[i]%=MOD;
		for(long long j = 0;j<=9;j++){
			if(j==7){//判断7 
				continue;
			}
			for(long long k = 0;k<7;k++){
				for(long long l = 0;l<7;l++){
					for(long long h = 0;h<=9;h++){
						if(h!=7){//判断7 
							node &v = dp[i][j][k][l],u = dp[i-1][h][mmod(k-j*e[i])][mmod(l-j)];
							v.cnt = mmmod(v.cnt+u.cnt);
							v.sum = mmmod(v.sum+1ll*j%MOD*(e[i]%MOD)%MOD*u.cnt%MOD+u.sum);
							v.res = mmmod(v.res+1ll*j%MOD*u.cnt%MOD*(e[i]%MOD)%MOD*j%MOD*(e[i]%MOD)%MOD+1ll*u.sum%MOD*2%MOD*j%MOD*(e[i]%MOD)%MOD+u.sum);
						}
					}
				}
			}
		}
	}
}
(3)利用新状态–问题再求解
问题的划分和上文相同,这里便不再赘述
 上文程序中的 
     
      
       
       
         g 
        
       
         e 
        
       
         t 
        
       
      
        get 
       
      
    get函数无需大改,只是需要返回结构体变量
 需要改的是 
     
      
       
       
         s 
        
       
         o 
        
       
         l 
        
       
         v 
        
       
         e 
        
       
      
        solve 
       
      
    solve函数
 我们原来使用的将答案累加到 
     
      
       
       
         a 
        
       
         n 
        
       
         s 
        
       
      
        ans 
       
      
    ans变量上的方式可以继续沿用
 为什么?因为将平方和加到一个现有的平方和的结果上,无需现有平方和结果对应的方案数和数的求和, 
     
      
       
       
         a 
        
       
         n 
        
       
         s 
        
       
      
        ans 
       
      
    ans还可以是 
     
      
       
       
         l 
        
       
         o 
        
       
         n 
        
       
         g 
        
       
         l 
        
       
         o 
        
       
         n 
        
       
         g 
        
       
      
        long long 
       
      
    longlong型的
 说人话就是求 
     
      
       
       
         r 
        
       
         e 
        
       
         s 
        
       
      
        res 
       
      
    res用不着 
     
      
       
       
         c 
        
       
         n 
        
       
         t 
        
       
         , 
        
       
         s 
        
       
         u 
        
       
         m 
        
       
      
        cnt,sum 
       
      
    cnt,sum管,不用开结构体变量
 至于累加平方和的公式又要再打一遍
 这就是本题的毒瘤之处
 其实那些公式推出来了,剩下的步骤思路难度不高,有的只是对手的折磨
(4)问题的终结–附上代码
话不多说,直接给代码(c++)
#include<bits/stdc++.h>
using namespace std;
const long long MOD = 1e9+7; 
long long e[30],g[30];//预处理10的幂
struct node{
	long long cnt,sum,res;
}dp[40][30][20][20];//状态 
long long mmod(long long x){//模7防负数 
	return (x%7+7)%7;
}
long long mmmod(long long x){//模1e9+7防负数
	return (x%MOD+MOD)%MOD;
}
long long n,a,b;
void init(){
	e[0] = g[0] = 1;//10^0
	e[1] = g[1] = 10;
	for(long long i = 0;i<=9;i++){//预处理个位数 
		if(i==7){
			continue;
		}
		node &u = dp[1][i][i%7][i%7];
		u.cnt++;
		u.sum+=i;
		u.res+=i*i;
	}
	long long pow = 10;
	for(long long i = 2;i<20;i++,pow*=10){
		e[i] = e[i-1]*10;
		e[i]%=7;
		g[i] = g[i-1]*10;
		g[i]%=MOD;
		for(long long j = 0;j<=9;j++){
			if(j==7){//判断7 
				continue;
			}
			for(long long k = 0;k<7;k++){
				for(long long l = 0;l<7;l++){
					for(long long h = 0;h<=9;h++){
						if(h!=7){//判断7 
							node &v = dp[i][j][k][l],u = dp[i-1][h][mmod(k-j*pow)][mmod(l-j)];
							v.cnt = mmmod(v.cnt+u.cnt);
							v.sum = mmmod(v.sum+1ll*j%MOD*(pow%MOD)%MOD*u.cnt%MOD+u.sum);
							v.res = mmmod(v.res+1ll*j%MOD*u.cnt%MOD*(pow%MOD)%MOD*j%MOD*(pow%MOD)%MOD+1ll*u.sum%MOD*2%MOD*j%MOD*(pow%MOD)%MOD+u.res);
						}
					}
				}
			}
		}
	}
}
node get(long long i1,long long j1,long long k1,long long l1){
	long long ans1 = 0,ans2 = 0,ans3 = 0;
	for(int k = 0;k<7;k++){
		for(int l = 0;l<7;l++){
			if(k!=k1&&l!=l1){
				node st = dp[i1][j1][k][l];
				ans1=mmmod(ans1+st.cnt);
				ans2=mmmod(ans2+st.sum);
				ans3=mmmod(ans3+st.res);
			}
		}
	}
	return {ans1,ans2,ans3};
}
long long solve(long long x){
	if(x==0){
		return 0;
	}
	long long ggg = x%MOD;
	long long h = x,s[1145],idx = 0,ans = 0,tmp1 = 0,tmp2 = 0;
	while(h){
		s[++idx] = h%10;
		h/=10; 
	}
	for(int i = idx;i>=1;i--){
		for(int j = 0;j<s[i];j++){
			if(j==7){
				continue;
			}
			long long k = mmod(-tmp1*e[i]),h = mmod(-tmp2);
			node st = get(i,j,k,h);
			ans = mmmod(ans+1ll*(tmp1%MOD)*(tmp1%MOD)%MOD*(g[i]%MOD)%MOD*(g[i]%MOD)%MOD*st.cnt%MOD+1ll*2*tmp1%MOD*(g[i]%MOD)%MOD*st.sum%MOD+st.res%MOD);
			
		}
		if(s[i]==7){
			break;
		}
		tmp1 = tmp1*10+s[i];
		tmp2+=s[i];
		if(i==1&&tmp1%7&&tmp2%7){
			ans = mmmod(ans+ggg*ggg%MOD);
		}
	}
	return ans;
} 
signed main(){
	init();
	cin>>n;
	while(n--){
		cin>>a>>b;
		long long ans = mmmod(solve(b)-solve(a-1));
		cout<<ans<<endl;
	}
	return 0;
}
5后记
我们就这样切掉了这道毒瘤题,作者认为这一题的难度完全可以评黑(下位黑或上位紫)
 作者从早上 
     
      
       
       
         10 
        
       
      
        10 
       
      
    10点调到晚上 
     
      
       
       
         8 
        
       
      
        8 
       
      
    8点,终于AC,并完成了这篇博客
 我觉得这一切都是值得的,我敢说我的博客比CSDN平台上的任何一篇都要详细
 我可以写出更详细的题解,这就是OI事业的发展
 可能某一天,我的题解也会成为"屎"一样的存在,那就证明OI的事业发展的更好了
 关注CSDN@森林古猿1,我会为大家带来更多胎教级教学
 本文作者是蒟蒻,如有错误请各位神犇指点
 森林古猿出品,必属精品,请认准CSDN森林古猿1


![mac中dyld[99014]: Library not loaded: @rpath/libmysqlclient.24.dylib解决方法](https://i-blog.csdnimg.cn/direct/cecbdffcc5ca4093985174d5f4ca23d8.png)
















