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]=\sum\limits_{i} (10^{len-1}if'+g')$
于是就完成了$g$的递推。$h$表示后面空位的数的平方和,也类似推法。
$h[len][sum][mod]=\sum\limits_{i} (10^{len-1})^2 i^2 f' + \sum\limits_{i} 2\times 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\n",(solve(R)-solve(L-1)+P)%P); 50 return 0; 51 }