95 D Horse Races

問題

4,7をラッキーな数とする。
自然数t,kが与えられる。t個の整数の組a[i],b[i]について以下をmod 10^9+7で求めよ。

  • a[i]以上,b[i]以下で、距離がk以下の二つのラッキーな数の組を一組以上含む数の数

制約条件

t,k≦1000
a[i],b[i]≦10^1000

方針

b[i]以下の求める数からa[i]-1以下の求める数を引けばよいので、
それぞれを計算してやる。


それぞれの計算はメモ化再帰による。
数字を先頭から見て行き、
現在の位置pos,最後にラッキーな数が現れた位置last,okかどうか、与えられた数よりsmallかどうか
であるような数の今までの数を、
rec(pos,last,ok,small)で表す。


smallが1のときは、a[i]やb[i]によらないので、メモ化できる。
smallじゃない時というのは、全桁がa[i](b[i])に一致しているときなので、1通りしかない。すなわちメモ化をしなくても間に合う。


よってsmallが1のときだけメモ化するメモ化再帰が使える。

ソースコード

const int mod=int(1e9+7);
int t,k;
int dp[1010][1010][2]; //pos, last, ok

int rec(string &d,int p,int last,bool ok,bool small){
	if(small&&dp[p][last+1][ok]>=0)return dp[p][last+1][ok];
	if(p==d.size())return ok;
	int ret=0;
	
	rep(i,10){
		int nlast=i==4||i==7?p:last;
		bool nok=ok, nsmall=small;
		if(last>=0&&nlast!=last&&nlast-last<=k)nok=1;
		if(i<d[p]-'0')nsmall=1;
		if(i==d[p]-'0'||nsmall)(ret+=rec(d,p+1,nlast,nok,nsmall))%=mod;
	}
	if(small)dp[p][last+1][ok]=ret;
	return ret;
}
void run()
{
	cin>>t>>k;
	rep(i,1010)rep(j,1010)rep(k,2)dp[i][j][k]=-1;
	rep(i,t){
		string a,b; cin>>a>>b;
		a=string(1001-a.size(),'0')+a; b=string(1001-b.size(),'0')+b;
		for(int j=1000;j>=0;j--){
			if(a[j]!='0'){
				a[j]--; break;
			}
			else a[j]='9';
		}
		ll ans=rec(b,0,-1,0,0)-rec(a,0,-1,0,0);
		if(ans<0)ans+=mod;
		cout<<ans<<endl;
	}
}