2. 卡片(结果填空)
小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个, 就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从 1 拼到多少。
例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10, 但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1 拼到多少?
代码实现:
package 第12届;
/*每张卡片上有数字0到9任一个数字,用这些卡片来拼一些数,从 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
*每张卡片只能用一次,问:从 1 拼到多少? 就是必须连续地从1开始往后拼!!
*分析:
*11 是用两个 1 拼出来的
*也就是说这一堆卡片消耗到哪个数字时不能拼出来,我们就输出这个数字的前一个数字!!!
*思路:
*1. 0到9 的卡片各 2021 张,利用while循环从1开始遍历,把当前遍历的数的每一位都取出来
*2. 判断每一位所对应的数字卡片的数量是否为0,若为0,说明此数字不能被拼凑出来,输出这个数字的前一个数字,即减1
*3. 若不为0,当前位的卡片数减1,继续向后循环
*4. 此处不知到位数,用n%10 从个位开始取 n/10 得到少个位后的数
*5. 还有break 只退出最里层的循环哦!!*/
public class T2 {
public static void main(String[] args) {
//定义数组,下标i代表数字为i的卡片 数组值就是所对应的张数
int[] ka = new int[10];
boolean isOut = false;
//初始各有2021张
for(int i=0;i<=9;i++) {
ka[i] = 2021;
}
int numNow = 1;//当前要拼凑的数字
while(true) {//不知道拼凑次数
int n = numNow;
while(n>=1) {//不知道要取出多少位
if(ka[n%10]==0) {
System.out.println(numNow-1);
isOut = true;
break;
}
ka[n%10]--;
n = n/10;
}
if(isOut==true) {
break;
}
numNow++;
}
}
//3181
}
3. 直线(结果填空)
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上, 那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点 {(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},即横坐标 是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数 的点。这些点一共确定了 11 条不同的直线。
给定平面上 20 × 21 个整点 {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},即横坐标是 0 到 19 (包含 0 和 19) 之间的整数、纵坐标是 0 到 20 (包含 0 和 20) 之 间的整数的点。请问这些点一共确定了多少条不同的直线。
代码实现:
package 第12届;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/*对于直线表达式y = kx +b 当两条直线的斜率k和截距b不完全相同时,就认为是两条不同的直线
* 两点确定一条直线:
* 1. 将两个点的坐标带入直线解析式中,求解k=(y1-y2)/(x1-x2) 求解b:可以通过一个点和k计算而得。
* 2. 可以把k和b存入HashSet中,使得重复的直线只储存一个数据。
* 3. k和b可能是小数,而小数在计算机中是有精度的,直接存小数,哪怕用double型也可能不准确。
* 所以我们用分数存储k和b,即k=kup/kdown; b=bup/bdown 且要用最简分数表示,否则不好比较是否相同。求最简分数可以先通过求分子分母的最大公约数,再同时除以最大公约数。
* 4. 以kup+" “+kdown+” “+bup+” "+bdown的字符串形式将直线存入HashSet。(k分子/k分母+“”+b分子/b分母)
* 5. 把坐标存入容器ArrayList中,形式是x*100+y(一个int型的数据)这个数除以100就是横坐标,对100取余就是纵坐标。
*/
public class T3 {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
// 将坐标以一个四位数的方式存入集合,x是百位千位,y是十位和个位。
for (int x = 0; x <= 19; x++) {
for (int y = 0; y <= 20; y++) {
set.add(x * 100 + y);
}
}
Set<String> ans = new HashSet<>();// 保存每一条直线的k+""+b
List<Integer> arr = new ArrayList<>(set);
int len = arr.size(); // 坐标个数
for (int i = 0; i < len; i++) {
int a = arr.get(i); // 取出一个坐标
for (int j = i + 1; j < len; j++) {
int b = arr.get(j); // 取出其他坐标
int x1 = a / 100, x2 = b / 100, y1 = a % 100, y2 = b % 100;
int up = y1 - y2, down = x1 - x2;
int c1 = gcd(up, down); // 求最大公约数
String k = (up / c1) + " " + (down / c1);// 斜率
if (down == 0) {
ans.add("x = " + x1); // 如果直线垂直与x轴则直接抛入ans集合,该情况共有19种。
continue;
}
int bup = y1 * down - up * x1;//b的分子 b的分母是down
int c2 = gcd(bup, down);
String B = (bup / c2) + " " + (down / c2);// 截距
ans.add(k + " " + B);
}
}
System.out.println(ans.size());//40257
}
// 求最大公约数
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
/*
* int bup = y1*down - up*x1;//b的分子 b的分母是down y1=(up/down)*x1+b b= y1 -(up/down)*x1 通分: y1*down /down - up*x1/down
*/
4. 货物摆放(结果填空)
小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝 规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、 宽、高。 小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上 分别堆 L、W、H 的货物,满足 n = L × W × H。
给定 n,请问有多少种堆放货物的方案满足要求。 例如,当 n = 4 时,有以下 6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、 2 × 2 × 1、4 × 1 × 1。
请问,当 n = 2021041820210418 (注意有 16 位数字)时,总共有多少种方案?
代码实现:
package 第12届;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/*具体思路:就是求出这个大数的所有因数,然后随便取三个看能不能得到它,妥妥的全排列问题。
*核心考点是[如何快速找出一个大数的所有因数]??? */
/*对于一个数n,它除以某个数m余数为零,就可以得到两个因子,一个因子是m,另一个是n/m
*因为假设数m=p*q,且p≤q则m=p*q≥p*p即p≤√m所以m必有一个小于或等于其平方根的因数,所以如果要求一个数的所有因子,你只要走到小于等于它的开平方数*/
public class T4 {
public static void main(String[] args) {
Set<Long> set = new HashSet<>();
Long n = 2021041820210418L;// 结尾加l表示是一个long型数
Long end = (long) Math.sqrt(n);// 检索因子的最大范围
for (Long i = (long) 1; i <= end; i++) {
if (n % i == 0) {
set.add(i);
set.add(n / i);
}
}
ArrayList<Long> factor = new ArrayList<>(set);
int count = 0;
for (int i = 0; i < factor.size(); i++) {
long a = factor.get(i);
for (int j = 0; j < factor.size(); j++) {
long b = factor.get(j);
if (a * b > n) {
continue;
}
for (int k = 0; k < factor.size(); k++) {
long c = factor.get(k);
if (a * b * c == n) {
count++;
}
}
}
}
System.out.println(count);//2430
}
}
5. 路径:
6. 时间限制:
小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取 了当前的时间,用一个整数表示,值为从 1970 年 1 月 1 日 00:00:00 到当前时 刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要 显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。
输入格式
输入一行包含一个整数,表示时间。
输出格式
输出时分秒表示的当前时间,格式形如 HH:MM:SS,其中 HH 表示时,值 为 0 到 23,MM 表示分,值为 0 到 59,SS 表示秒,值为 0 到 59。时、分、秒 不足两位时补前导 0。
样例输入 1
46800999
样例输出 1
13:00:00
样例输入 2
1618708103123
样例输出 2
01:08:23
代码实现:
package 第12届;
import java.util.Scanner;
/* 1s == 1000ms
* 思路是模拟 */
public class T5 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
long ms = scanner.nextLong();//注意开 long
//将单位小时和分用毫秒表示
long perhour = 60 * 60 * 1000;
long permin = 60 * 1000;
long hour = (ms/perhour)%24; // 保证小时在 [0, 23] 之内
ms = ms % perhour;//将小时数的余数,即剩下时间精确到分和秒
long minute = ms/permin;
ms = ms % permin;//将分钟数的余数,即剩下时间精确到秒
long sec = ms/1000;
System.out.format("%2s:%2s:%2s",check(hour),check(minute) ,check(sec));
}
public static String check(long x) {
return x<10 ? "0"+x : ""+x;
}
}