【CF ECR8-D】Magic Numbers(数位dp)

时间:2022-12-16 09:36:13

【CF ECR8-D】Magic Numbers(数位dp)


D. Magic Numbers
time limit per test:2 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

Consider the decimal presentation of an integer. Let's call a number d-magic if digit d appears in decimal presentation of the number on even positions and nowhere else.

For example, the numbers 1727374, 17, 1 are 7-magic but77,7,123, 34, 71 are not7-magic. On the other hand the number7 is0-magic,123 is2-magic,34 is4-magic and71 is1-magic.

Find the number of d-magic numbers in the segment[a, b] that are multiple ofm. Because the answer can be very huge you should only find its value modulo109 + 7 (so you should find the remainder after dividing by109 + 7).

Input

The first line contains two integers m, d (1 ≤ m ≤ 2000,0 ≤ d ≤ 9) — the parameters from the problem statement.

The second line contains positive integer a in decimal presentation (without leading zeroes).

The third line contains positive integer b in decimal presentation (without leading zeroes).

It is guaranteed that a ≤ b, the number of digits ina andb are the same and don't exceed2000.

Output

Print the only integer a — the remainder after dividing by109 + 7 of the number ofd-magic numbers in segment[a, b] that are multiple of m.

Examples
Input
2 6
10
99
Output
8
Input
2 0
1
9
Output
4
Input
19 7
1000
9999
Output
6
Note

The numbers from the answer of the first example are 16,26,36,46, 56, 76, 86 and96.

The numbers from the answer of the second example are 2,4,6 and8.

The numbers from the answer of the third example are 1767,2717,5757,6707, 8797 and 9747.


题目大意:

定义n-magic(0 <= n <= 9):从左往右,偶数位置均为n,奇数位置不为n的一类数

给出边界a b(数字a,b长度不超过2000) 要求找出[a,b]内所有可被m整除的d-magic个数


这里我用数位dp搞的 比赛时没注意整除m这条件 直接for循环按位搞 写完才发现 呵呵呵呵呵呵呵。。。。。

数位dp的思路是从高位往低位 传递所在位置 是否贴下限或上限或高位上下限重合 从高位到此的连续对m取余结果


然后搜就可以了 部分细节照着代码看比较好


<span style="font-size:18px;">#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread() freopen("in.in","r",stdin)
#define fwrite() freopen("out.out","w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int msz = 10000;
const double eps = 1e-8;

char a[2333],b[2333];
LL dp[2333][2333][3];
int m,d,len;

//high: 0-下界 1-上界 2-* 3-连续相等(可当成下界也可当成上界)
//pos:当前访问位置 md:连续取余结果
LL dfs(int high,int pos,int md)
{
	//len:串长+1 遍历完后返回余数是否为1(1则表示可被m整除)
	if(pos == len) return md == 0;

	//记忆化 缩短时间 high==3时可当成下界或上界(0/1)
	if(~dp[pos][md][high%3]) return dp[pos][md][high%3];

	LL ans = 0;
	int st,en;

	//纯低位则只能从下界开始
	st = (high != 2 && high != 1)? a[pos]-'0': 0;
	//纯高位则只能到上界
	en = (high != 2 && high != 0)? b[pos]-'0': 9;
	int nhigh;

	//奇数位置
	if(pos&1)
	{
		for(int i = st; i <= en; ++i)
		{
			//奇数位不可为d
			if(i == d) continue;

			//从高位到当前上下界一直相同
			if(high == 3 && st == en) nhigh = 3;
			//当前位置上下界已分离 高位到此恒下界或上下界恒相等 且当前也为下界
			else if((high == 0 || high == 3) && i == st) nhigh = 0;
			//当前位置上下界已分离 高位到此恒上界或上下界恒相等 且当前也为上界
			else if((high == 1 || high == 3) && i == en) nhigh = 1;
			//到当前处于上下界间
			else nhigh = 2;

			ans = (ans+dfs(nhigh,pos+1,(md*10+i)%m))%mod;
		}
	}
	//偶数位置 且包含d
	else if(st <= d && d <= en)
	{
		//从高位到当前上下界一直相同
		if(high == 3 && st == en) nhigh = 3;
		//当前位置上下界已分离 高位到此恒下界或上下界恒相等 且当前也为下界
		else if((high == 0 || high == 3) && st == d) nhigh = 0;
			//当前位置上下界已分离 高位到此恒上界或上下界恒相等 且当前也为上界
		else if((high == 1 || high == 3) && en == d) nhigh = 1;
		else nhigh = 2;

			//到当前处于上下界间
		ans = (ans+dfs(nhigh,pos+1,(md*10+d)%m))%mod;
	}

	//记录当前答案
	dp[pos][md][high%3] = ans;
	return ans;
}

int main()
{
	//fread();
	//fwrite();

	scanf("%d%d%s%s",&m,&d,a+1,b+1);

	memset(dp,-1,sizeof(dp));

	//len+1是为了方便作dfs截止条件
	len = strlen(a+1)+1;
	printf("%lld\n",dfs(3,1,0));

	return 0;
}



</span>