她的名字
单测试点时限: 4.0 秒
内存限制: 512 MB
“他走过一个又一个星球,
却始终放不下对她的思念。“
”深情终究是一趟孤独的旅程,
她是他永远的牵绊。”

我们每个人心中都有一只小狐狸。我们渴望被自己喜欢的人驯服。

爱情是彼此之间至为甜蜜的臣服。我们都是傻痴痴的小狐狸,徒具一副精明的外表。

就像你走到哪都挂念着她,想把她写进自己的歌里,成为你们共同的记忆。

你想从她全部由数字构成的名字里取出其中的 N 个数字,维持原来的顺序,组成结尾为数字 XY 的新词。

你自然希望自己的歌能够很长很长,歌词的每一句都能饱含甜蜜。

所以你想知道,她的名字能够组成多少个长度为 N 且结尾为数字 XY 的新词(如果从她名字中取出的任意一个数字位置不同,两个词就被认为是不同的)。
输入
第一行包含一个由数字构成的字符串 S (1≤|S|≤2 000)。

第二行包含一个整数 Q (1≤Q≤5⋅10^5),表示需要选择的不同结尾数量。

接下来的 Q 行,每行包含了一个整数 N (1≤N≤5⋅10^5) 和两个数字 XY,用空格隔开,表示需要选择的歌词的长度和结尾。

输出
对于每一个询问,输出一个整数,表示答案。

答案可能会很大,你只需要输出对于 109+7 取模后的结果。

样例
input
312121
4
2 21
3 31
4 22
3 22
output
3
0
1
2
提示
样例中第一个询问:312121, 312121, 312121.

第二个询问:无。

第三个询问:312121.

#include<cstdio>
#include<cstring>
using namespace std;
char s[2005];
char x,y;
int n;
const int mod=1e9+7;
long long c[2005][2005];//记忆化搜索求组合数 
bool book[10][10];//xy这个结尾是否算过 
int num[10][10][2005];//xy以及x的下标 ,储存的是x后有几个y 
long long a[2005][10][10];//n,x,y结果 
bool booka[2005][10][10];//n,x,y是否算过 
long long f(int n,int m) {   //求组合数 
	if(c[n][m]) return c[n][m];
	if(n<m) return 0;
	if(n==m||m==0) return 1;
	if(n>m)
		return c[n][m]=(f(n-1,m-1)+f(n-1,m))%mod;
}
int main() {
	scanf("%s",s+1);
	int len=strlen(s+1);
	int Q;
	scanf("%d",&Q);
	while(Q--) {
		scanf("%d ",&n);
		scanf("%c%c",&x,&y);
		int ans=0;
		if(!book[x-'0'][y-'0']) {  //xy结尾没算过 
			for(int i=len; i>=1; i--) {
				if(s[i]==x)
					num[x-'0'][y-'0'][i]=ans;
				if(s[i]==y)
					ans++;
			}
			book[x-'0'][y-'0']=true;
		}
		long long sum=0;
		if(n<=len&&n>=2) {  //2<=n<=len才有解(也是为了防止数组越界) 
			if(!booka[n][x-'0'][y-'0']) {//n,x,y这组数据没算过 
				for(int i=1; i<=len; i++) {
					if(num[x-'0'][y-'0'][i]) {
						sum+=num[x-'0'][y-'0'][i]*f(i-1,n-2)%mod;//(x后y的数目)*(从这个x前面的数里抽n-2个数有多少种情况) 
						sum%=mod;
					}
				}
				a[n][x-'0'][y-'0']=sum;
				booka[n][x-'0'][y-'0']=true;
			} else
				sum=a[n][x-'0'][y-'0'];
		}
		printf("%lld\n",sum);
	}
	return 0;
}