题目描述
给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:
注意:
1.加号与等号各自需要两根火柴棍
2.如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C>=0)
3.n根火柴棍必须全部用上
输入格式
输入文件matches.in共一行,仅一个整数n(n<=24)。
输出格式
输出文件matches.out共一行,表示能拼成的不同等式的数目。
样例
样例1输入
14
样例1输出
2
样例2输入
18
样例2输出
9
数据范围与提示
【输入输出样例1解释】
2个等式为0+1=1和1+0=1。
【输入输出样例2解释】
9个等式为:
0+4=4
0+11=11
1+10=11
2+2=4
2+7=9
4+0=4
7+2=9
10+1=11
11+0=11
分析
我们可以发现拼0123456789的火柴数是所有数基数,设一个大于9的数为 ,那么再设f[i]为整数拼i的火柴数,所以f[ ]=f[a1]+f[a2]+f[a3]+…,所以我们可以定义一个函数,来求得f[i],并且实现记忆化。
应为n≤24,所以最多有20根火柴拼数字,而我们打个暴搜,就可以发现,最大的且不超过24根的为711(7)+1(2)=712(10),因此,我们枚举到711即可
代码
#include <cstdio>
int a[10005] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
bool used[1000];
int point(int x) {
if(a[x] != 0) return a[x]; //如果a[x]已经有值了,直接返回
int sum = 0; //累加
int k = x; //复制一个
while(x > 0) {
sum += a[x % 10];
x /= 10;
}
a[k] = sum; //派上用场了QAQ
return sum;
}
int main() {
int n, ans = 0;
scanf("%d", &n);
if(n < 10) { //连1+1=1都拼不出来
printf("0");
return 0;
}
n -= 4;
for(int i = 0; i <= 711; i ++) {
for(int j = 0; j <= 711; j ++) {
if (used[i] == true && i == j) continue ; //如果i+i=2*i已经记录过了,就跳过
if(point(i) + point(j) + point(i + j) == n) {
++ ans;
}
if(i == j) used[i] = true;
}
}
printf("%d", ans);
return 0;
}
附录-暴搜代码
#include <cstdio>
#include <ctime>
#include <cstdlib>
#define max(a, b) a > b ? a : b
const int M = 2e5 + 15;
int a[M] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int point(int x) {
if(a[x] != 0) return a[x];
int sum = 0;
int k = x;
while(x > 0) {
sum += a[x % 10];
x /= 10;
}
a[k] = sum;
return sum;
}
int main() {
int maxn = -1;
for(int i = 1; i <= 100005; i ++) {
for(int j = 1; j <= 100005; j ++) {
if(point(i) + point(j) + point(i + j) <= 20) {
maxn = max(max(i, j), maxn);
printf("\n%d+%d=%d\n", i, j ,i + j);
printf("%d+%d+%d<=20", a[i], a[j], a[i + j]);
}
}
}
return 0;
}