位数问题

本文探讨了一类位数问题,即在所有N位数中找出含有偶数个数字3的数量,并通过取模操作避免结果过大。文章提供了两种算法实现方式:一种是朴素动态规划方法,另一种是对内存使用进行优化的降维处理方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
	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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值