题干:

As an exciting puzzle game for kids and girlfriends, the Matches Puzzle Game asks the player to find the number of possible equations A−B=CA−B=C with exactly n (5≤n≤500)n (5≤n≤500) matches (or sticks). 


In these equations, A,BA,B and CC are positive integers. The equality sign needs two matches and the sign of subtraction needs just one. Leading zeros are not allowed. 


Please answer the number, modulo a given integer m (3≤m≤2×109)m (3≤m≤2×109). 

Input

The input contains several test cases. The first line of the input is a single integer tt which is the number of test cases. Then t (1≤t≤30)t (1≤t≤30) test cases follow. 

Each test case contains one line with two integers n (5≤n≤500)n (5≤n≤500) and m (3≤m≤2×109)m (3≤m≤2×109).

Output

For each test case, you should output the answer modulo mm. 

Sample Input

4
12 1000000007
17 1000000007
20 1000000007
147 1000000007

Sample Output

Case #1: 1
Case #2: 5
Case #3: 38
Case #4: 815630825

解题报告:

   一眼上来就是搜索,谁能想到是数位dp、、太难了太难了、、

首先去掉3根火柴棒来凑成减号和等号,然后问题就变成了将剩下的火柴棒拼成B+C=A的形式。然后同时对ABC这三个数的同一个数位进行dp,注意这题dp的时候不是跟一般的数位dp一样是从高位到低位进行dp的,而是从低位像高位进行dp,因为这样方便记录前导零的问题。

参考题解,用dp[n][a][b][c]来表示剩余n根火柴棒时,从最低位开始的放法总数,a表示当前位是否有来自低一位的进位,b表示是否已停止放B这个数,c表示是否已停止放C这个数,则最终我们所求的结果就是dp[n-3][0][0][0]。

代码逻辑是这样的:

num[i]代表要凑出i这个数字需要的火柴个数。

每次检查当前剩余多少根火柴,如果<0直接return 0,然后如果b和c都已经停止了,那么直接进入出口,当然,出口中返回0或者1要检查是否合法:如果当前没有来自低一位的进位(又因为B和C已经停止了),所以你当前位也肯定是啥都没有,也就是要检查cnt是否=0;如果有来自低一位的进位,那么当前位一定是1,也就是看cnt是否==num[1]就行了。

然后就是枚举中间过程,注意这里只是用了数位dp的思想,所以不需要设置limit啥之类的东西,并且之类的res需要设置成longlong不然就爆int了。

然后就是分b和c这几种情况进行讨论,如果B和C都还没确定,那么就枚举他们分别取值是什么,然后通过B和C的取值就得到A对应位的取值(不难证明 一定是(B+C)%10,并且如果有进位,那么进位一定是1,可以通过小学学习的加法竖式简单证明)。

枚举好B和C之后,就有几种选择,可以让B停止,可以让C停止,也可以让B和C都停止,分别进行讨论就行了。注意B能停止的话,一定要保证i>0,同理C能停止的话,一定要保证j>0,因为不然就会出现前导零的情况使得这样就会出现前导零的情况,所以我们要避免这种情况发生,所以我没要特判一下i是否等于0,来进行下一步判断就可以了,其他的情况同理,就不再说了。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 555 + 5;
int t,iCase,n;
const int num[]= {6,2,5,5,4,5,6,3,7,6};
ll mod;
ll dp[555][2][2][2];
ll dfs(int cnt,int a,int b,int c) {
	if(cnt<0)return 0;
	if(~dp[cnt][a][b][c])return dp[cnt][a][b][c];
	if(b&&c) {
		if((a&&cnt==num[1])||(!a&&!cnt))return 1;
		else return 0;
	}
	ll res = 0;
	if(!b&&!c) {
		for(int i=0; i<=9; ++i)
			for(int j=0; j<=9; ++j) {
				res+=dfs(cnt-(num[i]+num[j]+num[(i+j+a)%10]),(i+j+a)/10,0,0);
				if(i)res+=dfs(cnt-(num[i]+num[j]+num[(i+j+a)%10]),(i+j+a)/10,1,0);
				if(j)res+=dfs(cnt-(num[i]+num[j]+num[(i+j+a)%10]),(i+j+a)/10,0,1);
				if(i&&j)res+=dfs(cnt-(num[i]+num[j]+num[(i+j+a)%10]),(i+j+a)/10,1,1);
			}
	} else if(!b) {
		for(int i=0; i<=9; ++i) {
			res+=dfs(cnt-(num[i]+num[(i+a)%10]),(i+a)/10,0,1);
			if(i)res+=dfs(cnt-(num[i]+num[(i+a)%10]),(i+a)/10,1,1);
		}
	} else if(!c) {
		for(int i=0; i<=9; ++i) {
			res+=dfs(cnt-(num[i]+num[(i+a)%10]),(i+a)/10,1,0);
			if(i)res+=dfs(cnt-(num[i]+num[(i+a)%10]),(i+a)/10,1,1);
		}
	}
	dp[cnt][a][b][c] = res % mod;
	return dp[cnt][a][b][c];
}
int main()
{
	cin>>t;
	while(t--) {
		memset(dp,-1,sizeof dp);
		scanf("%d%lld",&n,&mod);
		ll ans = dfs(n-3,0,0,0)%mod;
		ans = (ans+mod)%mod;
		printf("Case #%d: %lld\n",++iCase,ans);
	}
	return 0 ;
}