1313:【例3.5】位数问题
时间限制: 1000 ms 内存限制: 65536 KB
提交数:39515 通过数: 21452
【题目描述】
在所有的N𝑁位数中,有多少个数中有偶数个数字3?由于结果可能很大,你只需要输出这个答案对1234512345取余的值。
【输入】
读入一个数N(N≤1000)𝑁(𝑁≤1000)。
【输出】
输出有多少个数中有偶数个数字33。
【输入样例】
2
【输出样例】
73
【原题链接】
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)https://ybt.ssoier.cn/problem_show.php?pid=1313
分析
① 当N=1时,所有的一个数为0、1、2、3、4、5、6、7、8、9,其中,含偶数个3的数字为0、1、2、4、5、6、7、8、9,共9个。
② 当N=2时,分为两种情况:
如果第二个数字是3,那么第一个数字必也是3(两个3)-------(一种情况);
如果第二个数字不是3(九种情况),第一个数字也不是3且不能为0(八种情况),共8 x 9 = 72种可能。
如何得到n位数中包含偶数个3的方案数呢?
- 假设一个n位数最后一位数字是3,那么只有满足其前n - 1位包含奇数个3,才可以使n位包含偶数个3,即
f[n - 1][1]。
- 假设一个n位数最后一位数字不是3,可能取0、1、2、4、5、6、7、8、9(最后一位有9种情况),那么只有满足其前n - 1位包含偶数个3,才可以使n位包含偶数个3,即
f[n - 1][0] * 9。
综上,当N=2时,一共有73个数字包含偶数个3。
初始化一位数情况下的方案数:
- f[n][0]表示包含偶数个3的n位数的个数。
- f[n][1]表示包含奇数个3的n位数的个数。
int num = 9;
if (i == n) num = 8;
- 根据位数确定非首位元素可以为 0 的可能性数:
- 如果
i
不是 n,则有 9 种可能性(0 到 9)。 - 如果
i
是 n,则首位不能为 0,有 8 种可能性(1 到 9)。
- 如果
f[i][0] = (f[i - 1][1] + f[i - 1][0] * num) % 12345;
- 计算 i 位数中包含偶数个3的方案数:
- 从 i-1 位数中包含奇数个3的方案数转移过来,加上 i-1 位数中包含偶数个3的方案数乘以 num。
- 取模操作,避免数值溢出,模数为 12345。
f[i][1] = (f[i - 1][0] + f[i - 1][1] * num) % 12345;
- 计算 i 位数中包含奇数个3的方案数:
- 从 i-1 位数中包含偶数个3的方案数转移过来,加上 i-1 位数中包含奇数个3的方案数乘以 num。
- 同样进行模运算。
通过动态规划的思想计算了包含特定数量的数字3的 n 位数的方案数,使用了数组 f
来保存中间状态,从而避免了重复计算,提高了效率。
#include <iostream> //包含输入输出流头文件和使用标准命名空间。
using namespace std;
const int N = 1010; //常量定义 N,用于定义数组 f 的大小。
int f[N][2]; //二维数组 f,用来存储状态信息,f[i][0] 表示 i 位数中包含偶数个3的方案数,f[i][1] 表示 i 位数中包含奇数个3的方案数。
int main() //主函数开始。
{
int n;
cin >> n; // 输入变量 n,表示要计算包含 n 位数的方案数。
//f[1][0] 初始化为 9,即一位数中包含偶数个3的方案数(0, 1, 2, 4, 5, 6, 7, 8, 9)。
//f[1][1] 初始化为 1,即一位数中包含奇数个3的方案数(3)。
f[1][0] = 9;
f[1][1] = 1;
//递推
for (int i = 2; i <= n; i++) //开始递推计算从 2 到 n 位数的方案数。
{
int num = 9;
if (i == n) num = 8;
f[i][0] = (f[i - 1][1] + f[i - 1][0] * num) % 12345;
f[i][1] = (f[i - 1][0] + f[i - 1][1] * num) % 12345;
}
cout << f[n][0] << endl; //输出 n 位数中包含偶数个3的方案数。
return 0; //返回主函数结束。
}