假设递增数是指从左向右读时,其数字始终不小于前面的数字,例如:234559。
相反,在递减的数字中,从左到右的数字不会增加,例如:97732。
您不必成为新高斯也能理解一百以下的所有数字都属于这两个类别之一。
现在您需要创建一个函数来计算此类数字的数量,最多可达 10 的 n 次方(函数参数)。
全部的 | 以下 |
---|---|
1 | 1 |
10 | 10 |
100 | 100 |
第475章 | 1000 |
第1675章 | 10000 |
4954 | 100000 |
12952 | 1000000 |
#include <string>
#include <cmath>
using namespace std;
unsigned long long total_inc_dec(unsigned int n) {
string curr_num; unsigned long long total = 0; int isInc;
for (int i = 0; i < pow(10, n); i++) {
curr_num = to_string(i);
if (int(curr_num.length()) <= 2) {++total;}
else {
for (int it = 0; it < int(curr_num.length()); it++) {
if (it==0) {
if (curr_num[it] < curr_num[it+1]) {isInc = 1;}
if (curr_num[it] == curr_num[it+1]) {isInc = 0;}
if (curr_num[it] > curr_num[it+1]) {isInc = -1;}
}
else {
if (curr_num[it] < curr_num[it+1]) {
switch(isInc) {
case 1:
if (it == int(curr_num.length()) - 2) {
++total;
}
break;
case 0:
isInc = 1;
if (it == int(curr_num.length()) - 2) {
++total;
}
break;
case -1:
it = int(curr_num.length());
break;
}
}
if (curr_num[it] == curr_num[it+1]) {
if (it == int(curr_num.length()) - 2) {
++total;
}
}
if (curr_num[it] > curr_num[it+1]) {
switch(isInc) {
case -1:
if (it == int(curr_num.length()) - 2) {
++total;
}
break;
case 0:
isInc = -1;
if (it == int(curr_num.length()) - 2) {
++total;
}
break;
case 1:
it = int(curr_num.length());
break;
}
}
}
}
}
}
return total;
}
今天我几乎第一次听到“优化”这个词。我真的不知道该怎么做。
目前的解决方案...
...做了很多不必要的工作。所有数字均已整理并检查。没必要。例如,如果一个数字看起来像132xxxxxxx,那么它和它的所有邻居都可以被跳过。他们肯定不会通过考验。
路短...
...哈利在对该问题的评论中建议。你看到数字顺序了吗?在OEIS百科全书中找到它:https://oeis.org/search?q =1+10+100+475+1675+4954+12952 。不会有完全匹配,但会引用没有前导的序列:A364342。我们阅读文章,确保这是我们的序列,找到公式,对其进行编程,准备就绪。
如果你运气不好的话...
...并且没有找到序列,你将不得不用你的头脑来解决问题。我们将分别统计递增数和递减数。
数量不断增加
您需要经验来猜测n ,d - 恰好n位且第一位数字不小于d的递增数字的数量。事实:
我们对不断增加的最多n位数字感兴趣。让我们用n来表示它们。关注一个指标。
a n = 1 + Σ 1≤j≤n a j,1 – 您需要将所有合适长度的递增数相加,并加一为零。
代码直接重复了公式:
降序数字
方案是相同的:b n,d - 正好n位数字的降序数字链(不是数字 - 这在这里很重要),并且第一个数字不超过d。
我们对所有不超过n位的递减数字(这次不是链,数字)感兴趣。让我们用b n来表示它们。再次,注意一个指标。
b n = (Σ 1≤j≤n b j,9 ) - (n - 1) – 您需要添加所有合适长度的递增链并减去非数字链。有n-1 个这样的链:00 , 000 , 0000 , ...
“单调”数字
“单调”数字的数量c n:
c 0 = 1 – 对于n = 0 ,序列a和b未定义,需要单独定义;
其中n = a n + b n - 9·n - 1 – “单调”数字的数量是递增数字的数量加上递减数字的数量减去我们计算了两次的数字。零和所有数字都相同的数字会被计算两次:333、9999。这样的数有9·n 个。
动态规划
我的硬件上的这个解决方案在一秒钟内计算出c 25 = 236030401 。它比以前更好,但还可以更好。对于相同的参数,会重复调用
a(n, d)
和函数。b(n, d)
让我们用表格替换它们:对于n ≤ 375 ,此代码快速且正确地进行计数。c 375 = 17980269677772943001。然后就溢出了
unsigned long long
。计算需要微秒,你可以冷静一下。但有一种更快的方法并且代码更少。球和挡板方法
待办事项:继续
这是优化版本的样子: