通过删除总和不为 17 的连续数字对来计算删除的数字
Count numbers deleted by removing consecutive digit pairs that don't sum to 17
以下是我的问题陈述:
你得到一个以 10 为基数的数字,你必须通过选择两个连续的数字并删除它们来完全删除它。但是这2个数字的和不应该是17。我们把重复上述操作完全删除的数字称为"Good".
示例:
9889
=> 删除 88
得到 99
99
=> 删除 99
以完全删除号码。
结论:9889 好。
注意:我们不能删除 98
或 89
,因为这两个数字的总和是 17
.
给定一个数 N(even),你想找到 good N 位数模数 10^9 + 7
的数。也将包含前导零的 N 位数字也计入计数。
测试用例:
案例一:
Input: 2
Output: 98
案例二:
Input: 4
Output: 9926
案例三:
Input: 442
Output: 417551213
我试过使用各种代码解决这个问题,但无法得到结果。
尝试使用树来尝试所有可能的解决方案。真正的问题是,你必须预测哪些数字会保留下来,以及是否可以在总和为 17 的情况下删除它们。
例如,如果您有 9823,您可以删除 23,但最后会被 98 阻止。
你可以试着建一棵树,每个分支都有可能被删除。如果所有分支都被阻止,您将返回到前一个节点
对于最后一个可能的坏状态的每个序列,必须有一个强制序列产生它。查看可能的位置 wild-cards(提供选择的数字当然是感兴趣的数字),并尝试找到一种模式。
在下面的例子中,为了对称,把9换成8; x
s 是通配符:
输入长度 4,错误结果 9898:
9898
输入长度 4,错误结果 98:
989x
98x8
9x98
x898
从上面两个我们可以清楚的看出为什么会得到输出,9926个好的4位数字。
输入长度 6,错误结果 9898:
98989x
9898x8
989x98
98x898
9x9898
x89898
输入长度 6,错误结果 9898 或 98:
9898xx
989xx8
98xx98
9xx898
xx9898
输入长度 6,错误结果 98:
989x9x
98x8x8
...
9x989x
...
等等
Python代码:
# https://gist.github.com/rougier/ebe734dcc6f4ff450abf
def binom(n,k):
if not 0<=k<=n: return 0
b=1
for t in range(min(k,n-k)):
b*=n; b//=t+1; n-=1
return b
def f(n):
bads = 0
for k in range((n - 2) // 2 + 1):
bads += 9**k * binom(n, k)
return (10**n - 2 * bads) % (10**9 + 7)
print(f(442)) # 417551213
不想破坏编码,但数字是否正确,可以通过 回溯 来完成。
solve(9889);
public static void solve(int num) {
try {
solve(num, new LinkedList<>());
System.out.println("Not found");
} catch (FoundException fe) {
System.out.printf("%d%n", num);
fe.result.forEach(pair -> System.out.printf("-> %d, having deleted %d%n",
pair.getKey(), pair.getValue()));
}
}
private static class FoundException extends RuntimeException {
public final List<Pair<Integer, Integer>> result;
public FoundException(List<Pair<Integer, Integer>> result) {
this.result = result;
}
}
private static void solve(int num, LinkedList<Pair<Integer, Integer>> partialResult) {
if (num == 0) {
throw new FoundException(partialResult);
}
int tenPower = 1;
while (num >= tenPower) {
int n = num / tenPower;
int del = n % 100;
if (del % 10 + del / 10 != 17) {
int n2 = (n / 100) * tenPower + (num % tenPower);
partialResult.addLast(new Pair<>(n2, del));
solve(n2, partialResult);
partialResult.removeLast();
}
tenPower *= 10;
}
}
问题的表述似乎是 int
(31 位 unsigned int)就足够了。
因此,我尝试使用 int
而不是数字列表。
另一个功能:使用 return 的异常从深层内部递归到顶层并得到肯定的结果。传统的方法是检查递归调用的结果。
注意:实际问题是数学题。
以下是我的问题陈述:
你得到一个以 10 为基数的数字,你必须通过选择两个连续的数字并删除它们来完全删除它。但是这2个数字的和不应该是17。我们把重复上述操作完全删除的数字称为"Good".
示例:
9889
=> 删除88
得到99
99
=> 删除99
以完全删除号码。 结论:9889 好。 注意:我们不能删除98
或89
,因为这两个数字的总和是17
.
给定一个数 N(even),你想找到 good N 位数模数 10^9 + 7
的数。也将包含前导零的 N 位数字也计入计数。
测试用例:
案例一:
Input: 2
Output: 98
案例二:
Input: 4
Output: 9926
案例三:
Input: 442
Output: 417551213
我试过使用各种代码解决这个问题,但无法得到结果。
尝试使用树来尝试所有可能的解决方案。真正的问题是,你必须预测哪些数字会保留下来,以及是否可以在总和为 17 的情况下删除它们。 例如,如果您有 9823,您可以删除 23,但最后会被 98 阻止。
你可以试着建一棵树,每个分支都有可能被删除。如果所有分支都被阻止,您将返回到前一个节点
对于最后一个可能的坏状态的每个序列,必须有一个强制序列产生它。查看可能的位置 wild-cards(提供选择的数字当然是感兴趣的数字),并尝试找到一种模式。
在下面的例子中,为了对称,把9换成8; x
s 是通配符:
输入长度 4,错误结果 9898:
9898
输入长度 4,错误结果 98:
989x
98x8
9x98
x898
从上面两个我们可以清楚的看出为什么会得到输出,9926个好的4位数字。
输入长度 6,错误结果 9898:
98989x
9898x8
989x98
98x898
9x9898
x89898
输入长度 6,错误结果 9898 或 98:
9898xx
989xx8
98xx98
9xx898
xx9898
输入长度 6,错误结果 98:
989x9x
98x8x8
...
9x989x
...
等等
Python代码:
# https://gist.github.com/rougier/ebe734dcc6f4ff450abf
def binom(n,k):
if not 0<=k<=n: return 0
b=1
for t in range(min(k,n-k)):
b*=n; b//=t+1; n-=1
return b
def f(n):
bads = 0
for k in range((n - 2) // 2 + 1):
bads += 9**k * binom(n, k)
return (10**n - 2 * bads) % (10**9 + 7)
print(f(442)) # 417551213
不想破坏编码,但数字是否正确,可以通过 回溯 来完成。
solve(9889);
public static void solve(int num) {
try {
solve(num, new LinkedList<>());
System.out.println("Not found");
} catch (FoundException fe) {
System.out.printf("%d%n", num);
fe.result.forEach(pair -> System.out.printf("-> %d, having deleted %d%n",
pair.getKey(), pair.getValue()));
}
}
private static class FoundException extends RuntimeException {
public final List<Pair<Integer, Integer>> result;
public FoundException(List<Pair<Integer, Integer>> result) {
this.result = result;
}
}
private static void solve(int num, LinkedList<Pair<Integer, Integer>> partialResult) {
if (num == 0) {
throw new FoundException(partialResult);
}
int tenPower = 1;
while (num >= tenPower) {
int n = num / tenPower;
int del = n % 100;
if (del % 10 + del / 10 != 17) {
int n2 = (n / 100) * tenPower + (num % tenPower);
partialResult.addLast(new Pair<>(n2, del));
solve(n2, partialResult);
partialResult.removeLast();
}
tenPower *= 10;
}
}
问题的表述似乎是 int
(31 位 unsigned int)就足够了。
因此,我尝试使用 int
而不是数字列表。
另一个功能:使用 return 的异常从深层内部递归到顶层并得到肯定的结果。传统的方法是检查递归调用的结果。
注意:实际问题是数学题。