[Luogu-P4999烦人的数学作业]-数位DP

【题目地址】

题目意思见原题面。

很容易看出这是个数位DP。

考虑求 l ∼ r l\sim r lr区间内的数,我们可以转化为求 1 ∼ l − 1 1\sim l-1 1l1 1 ∼ r 1\sim r 1r,然后用前缀和的思想相减即可。

此时我们只用考虑上界(下界都为1了),套用数位DP的模板,我们记录一下当前的价值和后面出现了的数的个数即可。

#include
#include
#include
#define ll long long
using namespace std;
const ll Mod=1e9+7;
const int M=30;
struct node{
	ll cnt,val;
	void clear(){cnt=val=0;}
	node(){}
	node(ll a,ll b):cnt(a),val(b){}
}Rec[10][M];
bool vis[10][M];
int B[M],len;
node F(int num,int pos,bool ex){
	if(pos==1) return node(1,num);
	if(!ex&&vis[num][pos]) return Rec[num][pos];
	node now,to;now.clear();
	int r=ex?B[pos-1]:9;
	for(int i=0;i<=r;i++){
		to=F(i,pos-1,ex&&i==r);
		now.val=(now.val+1ll*num*to.cnt%Mod+to.val)%Mod;
		(now.cnt+=to.cnt)%=Mod;
	}	if(!ex){vis[num][pos]=1;Rec[num][pos]=now;}
	return now;
}
ll calc(ll v){
	if(v<=1) return v;
	len=0;
	memset(vis,0,sizeof(vis));
	while(v)B[++len]=v%10,v/=10;
	ll ans=0;
	for(int i=0;i<=B[len];i++){
		(ans+=(F(i,len,i==B[len]).val))%=Mod;
	}	return ans;
}	ll l,r;
int main(){
	int T;for(scanf("%d",&T);T--;){
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",((calc(r)-calc(l-1))%Mod+Mod)%Mod);
	}	return 0;
}

你可能感兴趣的:(题解)