📅  最后修改于: 2023-12-03 15:13:47.674000             🧑  作者: Mango
C运营商问题27是一道经典的算法问题,涉及到数字的位数操作和特殊的乘法规则,需要用到一些数学技巧。问题的描述如下:
给定一个数n,求出满足以下条件的数m的个数:
例如,当n=123,k=3时,满足条件的数有124、132、213、231、312、321共6个。
首先,我们需要理解题目中给出的乘法规则。因为在运算符只有加减乘的情况下,我们就可以把每个数拆分成一个个位数来处理,从而实现构造m的目的。
设n为k位数,其各个数位的值分别为a1、a2、……、ak。 先看n中各数位间的关系,以a1、a2、a3为例:
接着,我们需要考虑如何统计满足条件的m的个数。一个常用的方法是动态规划。
设f[i][j]表示第i位填入数字j时能构造出的不含0且大于n的数个数,最终答案即为f[k][0]~f[k][9]的和。
状态转移方程为:
最后,我们将从高到低每一位的f值累加起来即可得到答案。
以下为C++语言的代码实现:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 20;
int f[MAXN][12];
int a[MAXN];
int len;
signed main() {
int n; cin >> n;
while (n) {
a[++len] = n % 10;
n /= 10;
}
for (int i = 0; i <= 9; ++i) f[len][i] = (i >= a[len]);
for (int i = len - 1; i > 0; --i) {
for (int j = 0; j <= 9; ++j) {
int lim = j * a[i];
for (int k = j; k <= 9 && k <= lim; ++k) {
f[i][j] += f[i+1][k];
}
if (a[i+1] * j <= 9) continue;
lim = 9;
if (j * a[i+1] > 9) lim = a[i] - 1;
for (int k = 0; k <= lim; ++k) {
f[i][j] += f[i+1][k];
}
}
}
int ans = 0;
for (int i = 1; i <= 9; ++i) {
ans += f[1][i];
}
cout << ans << endl;
return 0;
}
以上代码基本实现了解题思路中所述的动态规划方法。