/*
Name: 位数问题
Copyright:
Author:
Date: 04-07-17 15:50
Description: 在所有的N位数中,有多少个数中有偶数个数字3?由于结果很大只需输出这个数mod12345
输入:读人一个数n (1 < n <= 1000)
输出: 输出有多少个数中有偶数个数字3
输入样例
2
输出样例
73
说明:包含0个三的有72个,包含2个3的数有1个,共73个。
算法思路:递推
可以用f[i][0]表示前i位取偶数(包含0)个3有几种情况,f[i][1]表示前i位取奇数个3有几种情况,则状态方程为:
f[i][0] = f[i-1][0] * 9 + f[i-1][1]; 分为第i位不是3和第i位是3两种情况
f[i][1] = f[i-1][1] * 9 + f[i-1][0]; 分为第i位不是3和第i位是3两种情况
第一式中f[i-1][0]*9表示第i位可以取除3以外的其他9个数字,前i-1位有偶数个3;f[i-1][1]表示第i位是3,则前i-1位有奇数个3;
第二式与第一式原理相似。
优化思路:降维
我们注意到 f[i][0](或f[i][1])只取决于f[i][0]和f[i][1] ,故可以用2个变量来代替数组:
用ai和bi分别代表f[i][0]和f[i][1],用ai_1和bi_1分别代表f[i-1][0]和f[i-1][1],则状态方程为:
ai = ai_1 * 9 + bi_1; 分为第i位不是3和第i位是3两种情况
bi = bi_1 * 9 + ai_1; 分为第i位不是3和第i位是3两种情况
*/
#include<iostream>
using namespace std;
int Fun_1(int n); //朴素动态规划算法
int Fun_2(int n); //降维优化
const int MODNUM = 12345; //为避免溢出,用来取模的数字
const int MAX = 1001;
int f[MAX][2]; //为理解方便,分别用f[1][0]和f[1][1]表示第1位取偶数个3和奇数个3
int main()
{
int n;
cin >> n;
cout << Fun_1(n) << endl;
cout << Fun_2(n) << endl;
return 0;
}
int Fun_1(int n) //朴素动态规划算法
{
f[1][0] = 9; //第1位有偶数(0)个3,即第1位可以去除了3以外的其他9个数字,有9种情况
f[1][1] = 1; //第1位有奇数(1)个3,即第1位取数字3,只有1种情况
for (int i=2; i<n; i++) //处理第2到第n-1位数,每位数均有取3或不取3两种可能,其中不取3时,可以取除3以外的其他9个数字
{
f[i][0] = (f[i-1][0] * 9 + f[i-1][1]) % MODNUM;
f[i][1] = (f[i-1][1] * 9 + f[i-1][0]) % MODNUM;
}
//单独处理第n位(最高位),因为最高位不能为0,故不取3时,只有8种可能
f[n][0] = (f[n-1][0] * 8 + f[n-1][1]) % MODNUM;
return f[n][0];
}
int Fun_2(int n) //降维优化
{
int ai, bi; //分别表示前i位取偶数(包含0)个3有几种情况,和前i位取奇数个3有几种情况
int ai_1 = 9; //第1位有偶数(0)个3,即第1位可以去除了3以外的其他9个数字,有9种情况
int bi_1 = 1; //第1位有奇数(1)个3,即第1位取数字3,只有1种情况
for (int i=2; i<n; i++) //处理第2到第n-1位数,每位数均有取3或不取3两种可能,其中不取3时,可以取除3以外的其他9个数字
{
ai = (ai_1 * 9 + bi_1) % MODNUM;
bi = (bi_1 * 9 + ai_1) % MODNUM;
ai_1 = ai; //迭代处理
bi_1 = bi; //迭代处理
}
//单独处理第n位(最高位),因为最高位不能为0,故不取3时,只有8种可能
ai = (ai_1 * 8 + bi_1) % MODNUM;
return ai;
}
位数问题
最新推荐文章于 2024-01-03 18:57:47 发布