hdu4507 吉哥系列故事——恨7不成妻[数位DP]

这题面什么垃圾玩意儿


首先看到问题格式想到数位DP,但是求的是平方和。尝试用数位DP推出。

先尝试拼出和。设$f[len][sum][mod]$表示填到$len$位,已填位置数位和$sum$,数字取余为$mod$时候的方案数,$g[len][sum][mod]$表示在这种情况下的所有满足要求的数的和(指的是后面剩余空位部分的数的和,前面填好的是不算的)。

那么枚举所填的数$i$,对于每一个满足要求的$x$,填上一个$i$之后变为

$10^{len-1}i+x$

(下$f[len-1][(sum+i)mod 7][(10mod+i)mod 7]$简记$f'$,$g,h$同理)

于是对于每一个$i$都有一次累加作用,这些$x$的和推过来应当是

$g[len][sum][mod]=sumlimits_{i} (10^{len-1}if'+g')$

于是就完成了$g$的递推。$h$表示后面空位的数的平方和,也类似推法。

$h[len][sum][mod]=sumlimits_{i} (10^{len-1})^2 i^2 f' + sumlimits_{i} 2 imes 10^{len-1} i f' + g'$

然后再每一次$i$的dfs完成之后进行递推。

注意这里的实现有一个小技巧,把$f,g,h$全部放结构体里,这样dp完一次之后直接取get他的整个包$f,g,h$,就不用考虑什么卡上界或者费事记录额外的东西了。

WA1:longlong输入又忘了。。

WA2:取模好好写。。不要老想着减少取模,不然会漏考虑的,万一真的要避免取模应当严格讨论加减乘除数的范围。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define dbg(x) cerr << #x << " = " << x <<endl
 7 using namespace std;
 8 typedef long long ll;
 9 typedef double db;
10 typedef pair<int,int> pii;
11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
16 template<typename T>inline T read(T&x){
17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
19 }
20 const int P=1e9+7;
21 int bin[20],bin2[20];
22 struct thxorz{
23     int f,g,h;
24     thxorz(int f=-1,int g=0,int h=0):f(f),g(g),h(h){}
25 }f[20][7][7];
26 int b[20];
27 int T;
28 ll L,R;//mistake
29 thxorz dp(int len,int sum,int mod,int limit){
30     if(!len)return thxorz(sum&&mod,0,0);
31     if(!limit&&~f[len][sum][mod].f)return f[len][sum][mod];
32     int num=limit?b[len]:9;
33     thxorz ret,tmp;ret.f=0;
34     for(register int i=0;i<=num;++i)if(i^7){
35         tmp=dp(len-1,(sum+i)%7,(mod*10+i)%7,limit&&i==num);//mistake2
36         ret.f+=tmp.f;ret.f>=P&&(ret.f-=P);
37         ret.g=(tmp.g+bin[len-1]*1ll*tmp.f%P*i+ret.g)%P;
38         ret.h=(bin2[len-1]*1ll*tmp.f%P*i*i+tmp.h+2*bin[len-1]*1ll*tmp.g%P*i+ret.h)%P;
39     }
40     return limit?ret:f[len][sum][mod]=ret;
41 }
42 inline int solve(ll x){
43     int len=0;while(x)b[++len]=x%10,x/=10;
44     return dp(len,0,0,1).h;
45 }
46 
47 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
48     for(register int i=0,res=1;i<=18;++i,res=res*1ll*10%P)bin[i]=res,bin2[i]=res*1ll*res%P;
49     read(T);while(T--)read(L),read(R),printf("%d
",(solve(R)-solve(L-1)+P)%P);
50     return 0;
51 }
View Code