蓝桥杯31天冲刺之二十三 [java]

打包

image-20220330122631432

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2978

这个是一道二分的题目,题目需要求的最大重量肯定是介于[单件物品最大重量,所有物品总质量之间的],这个肯定是没有问题的,然后我们就需要在这个区间中二分查找满足条件的答案即可,对于check函数我们只需要检查在每个包裹的最大重量不超过传入的targetWeight时能打包几个包裹就行,当可以打包的包裹数小于等于需要的包裹数时,说明这个重量是可以满足的,就可以去查找更小的质量是不是也满足

为什么当可以打包的包裹数小于等于需要的包裹数时,说明这个重量是可以满足的

因为当你使用更少的包裹就可以完成这个重量要求的时候,随便从一个包裹里面拿几件出来拼成另一个包裹也是可以满足的,也就是说包裹可以用的比要求的少,但是不能更多

package daily;

import java.util.Scanner;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2978
 * 
 * @author Jia
 *
 */
public class day3_30_1 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt();
		int M = sc.nextInt();

		int[] weights = new int[N];
		int maxWeight = 0;// 所有物品的最大重量
		int sumWeight = 0;// 所有物品的总重量
		for (int i = 0; i < weights.length; i++) {
			weights[i] = sc.nextInt();
			maxWeight = Math.max(maxWeight, weights[i]);
			sumWeight += weights[i];
		}
		sc.close();

		// 二分寻找满足条件的最小重量
		int left = maxWeight;
		int right = sumWeight;
		while (left <= right) {
			int mid = (right - left) / 2 + left;
			if (check(weights, mid, M)) {
				// 当这个重量可以满足的时候继续往左边查找
				right = mid - 1;
			} else {
				// 这个重量不能拼出来的时候向右边查找
				left = mid + 1;
			}
		}
		System.out.println(left);
	}

	/**
	 * 判断当前是否可以满足打包成packNum个包裹,且每个质量均不超过`targetWeight`
	 * 
	 * @param weights
	 * @param targetWeight
	 * @param packNum
	 * @return 如果可以则返回true,否则返回false
	 */
	private static boolean check(int[] weights, int targetWeight, int packNum) {
		int curWeight = 0;
		int curPackNum = 0;

		for (int i = 0; i < weights.length; i++) {
			if (curWeight + weights[i] > targetWeight) {
				curPackNum++;
				curWeight = 0;
			}
			curWeight += weights[i];
		}
		curPackNum++;
		return curPackNum <= packNum;
	}
}

约数个数

image-20220330132000495

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2606

这个想不到好的方法就直接暴力上了,看到了数据规模,估摸着应该能过一半把,然后最后拿了60%,还挺不错

方法类似于筛选素数的方法,从小向大遍历,遍历到一个数直接给它的因数加一,同时给ans加上当前数因数的数目并取余直到结束

其实还想用打表做来着,直接把10000000个数据直接放数组中然后提交了,但是输出的时候卡了好久出不来,就放弃了(或许也可以直接输出到文件中,看他的内存限制是512MB,10^7个int数字也就大概占用50MB吧,感觉方法还是可行的hhh)

package daily;

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

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2606
 * 
 * @author Jia
 *
 */
public class day3_30_2 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		sc.close();

		int[] arr = new int[n + 1];
		int ans = 1;
		int[] ansArr = new int[n + 1];
		Arrays.fill(arr, 1);// 使用1填充数组

		// 统计约数的数量
		for (int i = 2; i < arr.length; i++) {
			int j = i;
			while (j < arr.length) {
				arr[j] = (arr[j] + 1) % (1000000007);
				j += i;
			}
			ans = (ans + arr[i]) % (1000000007);
			ansArr[i] = ans;
		}
		System.out.println(ans);
	}
}

寻找三位数

image-20220330134514156

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T2038

这个题常规题,直接dfs获得所有的排列数,然后判断每种排列是不是满足条件就OK了

建议把这个题直接当获取排列数的模板记下,其他题中只需要更改check函数中的内容就行了

package daily;

/**
 * http://lx.lanqiao.cn/problem.page?gpid=T2038
 * 
 * @author Jia
 *
 */
public class day3_31_3 {
	static int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	public static void main(String[] args) {
		dfs(0);// 深度有限遍历所有排列数
	}

	/**
	 * dfs获得所有排列数
	 * 
	 * @param index
	 */
	private static void dfs(int index) {
		if (index == arr.length) {
			check();
		} else {
			for (int i = index; i < arr.length; i++) {
				swap(i, index);
				dfs(index + 1);
				swap(i, index);
			}
		}
	}

	/**
	 * 检查当前排列是否满足条件
	 */
	private static void check() {
		int num1 = getVal(0, 3);
		int num2 = getVal(3, 6);
		int num3 = getVal(6, 9);
		if (num1 * 2 == num2 && num1 * 3 == num3) {
			System.out.println(num1 + " " + num2 + " " + num3);
		}
	};

	/**
	 * 将arr在区间[begin,end)中的值转换为int返回
	 * 
	 * @param begin
	 * @param end
	 * @return
	 */
	private static int getVal(int begin, int end) {
		int ret = 0;
		for (int i = begin; i < end; i++) {
			ret = ret * 10 + arr[i];
		}
		return ret;
	}

	/**
	 * 交换数组两个位置的元素
	 * 
	 * @param i
	 * @param j
	 */
	private static void swap(int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

第二点五个不高兴的小明

题目链接:http://lx.lanqiao.cn/problem.page?gpid=T770

这个题应该是动态规划做的,不过限制比较难的就是要求必须要经过t次到达终点,和常规的上台阶相比难了一点点

还是一样的,定义dp数组,有t+1行,n+2列,其中 d p [ i ] [ j ] dp[i][j] dp[i][j]表示第 i i i步到达第 j j j个格子时的最大权重

因此,递归方程可以写出来为:
d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j − m ] + w e i g h t [ j − 1 ] ) , ( 其 中 m ∈ [ 1 , p ] ) dp[i][j]=max(dp[i][j], dp[i-1][j-m]+weight[j-1]),(其中m\in[1,p]) dp[i][j]=max(dp[i][j],dp[i1][jm]+weight[j1]),(m[1,p])
然后需要将数组的所有元素都先初始化为Intger.MIN_VALUE,这样可以保证权重比0小时发生更新的错误,然后第一步的值也需要预先更新好


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hydrion-Qlz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值