题意: 用n<=500火柴 正好摆出A-B=C 求方法数 不能有前导0
分析: dp 貌似火柴的题 应该是这种数字的题 都有差不多的状态 首先将等式变成B+C=A 易于计算
考虑状态dp[left][carry][placeB][placeC] := dp[500][0/1][0/1][0/1]
从低位到位放置数字 剩余多少根火柴 是否有进位 B是否放置 C是否放置
至于怎么转移 看第一种情况 B&&C 我相信你就懂了 有了状态这种题还是很好写的
代码:
//
// Created by TaoSama on 2015-09-25
// Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
typedef long long LL;
int n, m;
LL dp[505][2][2][2]; //left, carry, place B, place C
int need[] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
void add(LL& x, LL y) {
x += y;
if(x >= m) x -= m;
}
LL dfs(int n, bool carry, bool B, bool C) {
LL& ret = dp[n][carry][B][C];
if(~ret) return ret;
if(n == 0) {
if(!carry && !B && !C) return ret = 1;
return ret = 0;
}
ret = 0;
if(B && C) {
for(int i = 0; i < 10; ++i) {
for(int j = 0; j < 10; ++j) {
int sum = need[i] + need[j] + need[(i + j + carry) % 10];
if(sum > n) continue;
bool nxt = i + j + carry >= 10; //check next carry
//always can continue to place B & C
add(ret, dfs(n - sum, nxt, 1, 1));
if(i) add(ret, dfs(n - sum, nxt, 0, 1)); //choose not to place B
if(j) add(ret, dfs(n - sum, nxt, 1, 0)); //choose not to place C
if(i && j) add(ret, dfs(n - sum, nxt, 0, 0)); //choose neither place
}
}
} else if(B) {
for(int i = 0; i < 10; ++i) {
int sum = need[i] + need[(i + carry) % 10];
if(sum > n) continue;
bool nxt = i + carry >= 10;
add(ret, dfs(n - sum, nxt, 1, 0));
if(i) add(ret, dfs(n - sum, nxt, 0, 0));
}
} else if(C) {
for(int j = 0; j < 10; ++j) {
int sum = need[j] + need[(j + carry) % 10];
if(sum > n) continue;
bool nxt = j + carry >= 10;
add(ret, dfs(n - sum, nxt, 0, 1));
if(j) add(ret, dfs(n - sum, nxt, 0, 0));
}
} else {
if(carry && n == need[1]) ret = 1;
}
return ret;
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
int t; scanf("%d", &t);
int kase = 0;
while(t--) {
scanf("%d%d", &n, &m);
n -= 3; //subtract - & = signs' cost
memset(dp, -1, sizeof dp);
printf("Case #%d: %I64d\n", ++kase, dfs(n, 0, 1, 1));
}
return 0;
}