蓝桥杯每日一题-----数位dp练习

news/2024/7/24 0:52:16 标签: 蓝桥杯, 算法, 深度优先

题目

在这里插入图片描述
链接

参考代码

写了两个,一个是很久以前写的,一个是最近刚写的,很久以前写的时候还不会数位dp所以写了比较详细的注释,这两个代码主要是设置了不同的记忆数组,通过这两个代码可以理解记忆数组设置的灵活性。


import java.util.Scanner;



public class Main {
	// 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
	static int[] b = new int[15];
	static long[][][] f = new long[15][10][15];

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		long n = scanner.nextLong();
		long m = scanner.nextLong();
		for (int i = 0; i < 15; i++) {
			for (int j = 0; j < 10; j++) {
				for (int j2 = 0; j2 < 15; j2++) {
					f[i][j][j2] = -1;
				}
			}
		}
		for (int i = 0; i <= 9; i++) {
			System.out.print((get(m, i) - get(n - 1, i)) + " ");
		}

	}

	private static long get(long x, int target) {
		// TODO Auto-generated method stub
		long t = x;
		int i = 0;
		while (t > 0) {
			b[i++] = (int) (t % 10);
			t = t / 10;
		}
		return dfs(target, true, true, i - 1, 0);
	}

//	target  表示要计算的值
//	e  是否贴上界
//当要判断的数的位数小于原数的位数时,就没有上界了,如果位数和原数一样,每一位的上界就是对应的原数
//	first  是否是数的第一个位
//	k  数的第几位 now
//  t  出现的次数
	private static long dfs(int target, boolean e, boolean first, int k, int t) {
		// TODO Auto-generated method stub
		//

		long res = 0;
		if (k == -1)
			return t;// 如果数位考虑完,返回出现的次数
		// f[k][target][t]时公用的,找这个x的时候可以用,找下一个x的时候也可以用,所以他应该具有普遍性,
		// 但是当我的位数和x一样时,他有不同的边界
		if ((!e) && (!first) && f[k][target][t] != -1)
			return f[k][target][t];
		// 判断这一位我可以最大填到哪个数
		int u = e ? b[k] : 9;
		// 如果是要填写首位数,那么这个数等于0的时候其实位数是减一,要单独考虑。
		if (first) {
			res += dfs(target, false, true, k - 1, t);
		}
		// 注意我已经判断了如果要给首位填数,首位数为0的情况,所以当要给首位填数时,我要从1开始,如果不是首位,那么从0开始即可
		for (int i = first ? 1 : 0; i <= u; i++) {
			// 贴上界是指此时的位数的上界是受此位的数的限制,最大数可能到达不了9
			// 只有本位是贴上界的下一位才有贴上界的可能,比如54321,只要是第五位他的上界就是5,也就是此位最大取到5,
			// 这也就是为什么在get中一开始遍历的时候e = true
			// 当确定了这个数是5位的时候,如果第五位小于5,那他后面的数是不贴上界的最大值可以写到9,但如果第五位等于5
			// 那下一位也是贴上界的,最大值只能取到4
			// (i == u) & e 这也是它的来源
			res += dfs(target, (i == u) & e, false, k - 1, (i == target) ? t + 1 : t);
		}
		// f[k][target][t]时公用的,找这个x的时候可以用,找下一个x的时候也可以用,所以他应该具有普遍性,
		// 但是当我的位数和x一样时,他有不同的边界限制,此时他得出的值具有个性,不能给其他的x用,所以不能存在f数组中
		// 这是为什么要判断是否贴上界的原因
		// 当该位数为一个数的首位时,因为此时该数的实际位数是不确定的,首位为0时实际位数会减少,但我依然记录在res中,这样此时的
		// (f[k][target][t] 就有两种情况一是k是首位的时候,二是k不是首位的时候,所以我们应该舍去k时首位的时候
		if (!e && !first) {
			f[k][target][t] = res;
		}
		return res;
	}
}

import java.util.Arrays;
import java.util.Scanner;

public class 数字计数 {
	static long dp[][][][] = new long[15][10][15][2];
public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	long a = scanner.nextLong();
	long b = scanner.nextLong();
	for(int i = 0;i < 15;i++)
		for(int j = 0;j < 10;j++)
			for(int k = 0;k < 15;k++)
				Arrays.fill(dp[i][j][k], -1);
	for(int i = 0;i < 10;i++)
	   System.out.print(solve(b,i)-solve(a-1,i)+" ");//20 21 2 12 22 32 42 52 62 72 82 92 23 24 25 26 27 28 29
//	System.out.println(solve(b, 2));//2 12 20-29(10) 32 42 52 62 72 82 92 22
}
static int nums[] = new int[15];
static int temp[] = new int[15];
static int tot = 0;
private static long solve(long n,int k) {
	// TODO Auto-generated method stub
	tot=0;
	while(n > 0) {
		nums[++tot] = (int) (n % 10);
		n /= 10;
	}
	return dfs(tot,1,1,k,0);
}
private static long dfs(int cnt, int limit, int zeros, int k, int num) {
	// TODO Auto-generated method stub
	if (cnt==0) {
//		for(int i = 1;i <= 2;i++) System.out.print(temp[i]);
//		System.out.println( " "+ num);
		return num;
	}
	if(limit==0&&dp[cnt][k][num][zeros]!=-1) return dp[cnt][k][num][zeros];
	int up = limit==1?nums[cnt]:9;
	int st = zeros==1?1:0;
	long res = 0;
	if(zeros==1)  res+=dfs(cnt-1, (0==up?1:0)&limit, 1, k, num);//该位填0
	for(int i = st;i <= up;i++) {
//		temp[cnt]=i;
		res+=dfs(cnt-1, (i==up?1:0)&limit, 0, k, i==k?num+1:num);
	}
	if(limit==0) dp[cnt][k][num][zeros]=res;
	return res;
}
}


http://www.niftyadmin.cn/n/5366767.html

相关文章

opencv0014 索贝尔(sobel)算子

前面学习的滤波器主要是用来模糊图像&#xff0c;今天一起来了解关于边缘识别的滤波吧&#xff01;嘿嘿 边缘 边缘是像素值发生跃迁的位置&#xff0c;是图像的显著特征之一&#xff0c;在图像特征提取&#xff0c;对象检测&#xff0c;模式识别等方面都有重要的作用。 人眼如…

docker复习笔记01(小滴课堂)安装+部署mysql

查看内核版本。 关闭防火墙&#xff1a; 查看docker版本&#xff1a; 下载阿里yum源&#xff1a; 再看一下yum版本都有哪些&#xff1a; 我们可以看的docker-ce了。 安装它&#xff1a; 设置docker服务开机启动&#xff1a; 更新日志文件&#xff1a; 启动docker&#xff1a; …

Java开发IntelliJ IDEA2023

IntelliJ IDEA 2023是一款强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为Java开发人员设计。它提供了许多特色功能&#xff0c;帮助开发人员更高效地编写、测试和调试Java应用程序。以下是一些IntelliJ IDEA 2023的特色功能&#xff1a; 智能代码编辑器&…

机器学习---概率图模型(隐马尔可夫模型、马尔可夫随机场、条件随机场)

1. 隐马尔可夫模型 机器学习最重要的任务是根据已观察到的证据&#xff08;例如训练样本&#xff09;对感兴趣的未知变量&#xff08;例如类别标 记&#xff09;进行估计和推测。概率模型&#xff08;probabilistic model&#xff09;提供了一种描述框架&#xff0c;将描述任…

用的到的linux-删除文件-Day3

前言&#xff1a; 上一节&#xff0c;我们讲到了怎么去移动文件&#xff0c;其中使用到两大类的脚本命令即cp和mv。各两种命令都可以完成移动&#xff0c;但是cp是复制粘贴的方式&#xff0c;可以选择原封不动的复制粘贴过来&#xff0c;即不修改文件及文件夹的创建时间等&…

App Store外区账号分享

App Store外区账号分享及注意事项 外区苹果ID分享指南什么是外区苹果ID&#xff1f;为什么需要外区苹果ID&#xff1f;获取方法分享外区苹果ID的注意事项方式2获取步骤 外区苹果ID分享指南 在数字时代&#xff0c;我们的生活与各种应用和服务紧密相连。 对于苹果用户而言&#…

Qt程序设计-读写CSV文件

本文实例演示Qt读写CSV文件实现 创建项目 添加两个按钮和一个显示路径的label 界面如下 UI界面 <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"><class>MainWindow</class><widget class="QM…

2024年信息管理与工业制造与自动化国际学术会议(ICIMIMA2024)

2024年信息管理与工业制造与自动化国际学术会议(ICIMIMA2024) 会议简介 2024年信息管理与工业制造及自动化国际学术会议&#xff08;ICIMIMA2024&#xff09;将在中国三亚举行。会议旨在为信息管理和工业工程领域的专家、学者、工程师和技术人员提供一个平台&#xff0c;分享…