2018.09.27 hdu4507吉哥系列故事——恨7不成妻(数位dp)

时间:2023-03-09 06:01:39
2018.09.27 hdu4507吉哥系列故事——恨7不成妻(数位dp)

传送门

一道比较综合的数位dp。

维护三个值:[L,R][L,R][L,R] 区间中与7无关的数的数量,与7无关的数之和,与7无关的数的的平方和。

然后可以用第一个值推第二个,第一个和第二个值推第三个。

代码:

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
ll L,R,mul[30];
int t,len,num[20];
struct DP{ll c,s1,s2;}f[30][10][10];
inline DP dfs(int pos,int m1,int m2,bool lim){
	if(pos==0)return (DP){(m1&&m2),0ll,0ll};
	if(~f[pos][m1][m2].c&&!lim)return f[pos][m1][m2];
	DP ret=(DP){0ll,0ll,0ll};
	int up=lim?num[pos]:9;
	for(int i=0;i<=up;++i){
		if(i==7)continue;
		DP tmp=dfs(pos-1,(m1+i)%7,(m2*10+i)%7,lim&&i==up);
		(ret.c+=tmp.c)%=mod;
		(ret.s1+=tmp.s1+tmp.c*mul[pos]%mod*i%mod)%=mod;
		(ret.s2+=((tmp.c*(mul[pos]*mul[pos]%mod)%mod)%mod*i%mod*i%mod+tmp.s2)%mod+tmp.s1*2%mod*mul[pos]%mod*i%mod)%=mod;
	}
	if(!lim)f[pos][m1][m2]=ret;
	return ret;
}
inline ll solve(ll x){
	if(!x)return 0;
	len=0;
	while(x)num[++len]=x%10,x/=10;
	return dfs(len,0,0,1).s2;
}
int main(){
	memset(f,-1,sizeof(f));
	mul[1]=1;
	for(int i=2;i<=20;++i)mul[i]=mul[i-1]*10%mod;
	scanf("%d",&t);
	while(t--)scanf("%lld%lld",&L,&R),printf("%lld\n",((solve(R)-solve(L-1))%mod+mod)%mod);
	return 0;
}