A题:门牌制作【5分】
【题目描述】
小蓝要为一条街的住户制作门牌号。
这条街一共有2020 位住户,门牌号从1 到2020 编号。
小蓝制作门牌的方法是先制作0 到9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌1017 需要依次粘贴字符1、0、1、7,即需要1 个字符0,2 个字符1,1 个字符7。
请问要制作所有的1 到2020 号门牌,总共需要多少个字符2?
【答案】624
【题解】简单枚举,从1到2020遍历,对数字的每一位进行判断,如果某一位的字符为2,则加1.
代码:
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
int ans = 0;
for(int i = 1; i <= 2020; i++) {
int x = i;
while(x > 0) {
if(x % 10 == 2) ans++;
x /= 10;
}
}
System.out.println(ans);
}
}
题B:寻找2020【5分】
【题目描述】
小蓝有一个数字矩阵,里面只包含数字0 和2。小蓝很喜欢2020,他想找到这个数字矩阵中有多少个2020 。
小蓝只关注三种构成2020 的方式:例如,对于下面的矩阵:
- 同一行里面连续四个字符从左到右构成2020。
- 同一列里面连续四个字符从上到下构成2020。
- 在一条从左上到右下的斜线上连续四个字符,从左上到右下构成2020。
220000 000000 002202 000000 000022 002020一共有5 个2020。其中1 个是在同一行里的,1 个是在同一列里的,3 个是斜线上的。 小蓝的矩阵比上面的矩阵要大,由于太大了,他只好将这个矩阵放在了一个文件里面。
在本试题中有一个文件2020.txt,里面给出了小蓝的矩阵。
请帮助小蓝确定在他的矩阵中有多少个2020。
这是一道结果填空的题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【答案】16520
【题解】题目给出条件需要从左到右,从上到下,从左上到右下三种条件下是2020才可以。而且题目要求需要读出文件中的所有满足条件的2020.首先可以将文件中有多少行读出,然后以字符串的形式输入文件中的内容,并用数组保存,然后开始遍历寻找一共有多少个2020.
代码:
//计算文件2020.txt中含有多少行
public class Main{
public static void main(String[] args) throws IOException {
File file = new File("D:\\2020.txt");
InputStreamReader read = new InputStreamReader(new FileInputStream(file),"utf-8");
BufferedReader in = new BufferedReader(read);
String str = null;
int cnt = 0;
while ((str = in.readLine()) != null) {
cnt++;
}
System.out.println(cnt);
in.close();
}
}//300行
import java.util.Scanner;
//由上边代码已知一共300行,下面可以验证每行有300列
public class Main {
static int N = 310;
static int g[][] = new int[N][N];
public static void main(String[] args) {
Scanner sc = new Scanner( System.in);
for(int i = 1; i <= 300; i ++) {//将300行字符串直接输入
String s = sc.next();
// System.out.println(s.length());//300列
for(int j = 0; j < 300; j++) {//保存在g[][]数组中
char ch = s.charAt(j);
g[i][j+1] = ch - '0';
}
}
int ans = 0;//记录答案
for(int i = 1; i <= 300; i++) {//300行
for(int j = 1; j <= 300; j++) {//300列
//每行最多走到第297列,后面还有三列,是最右边的2020
if(j <= 297 && g[i][j] == 2 && g[i][j+1] == 0 && g[i][j+2] == 2 && g[i][j+3] == 0) ans++;
//每列最多走到第297行,后面还有三行,是最下边的2020
if(i <= 297 && g[i][j] == 2 && g[i+1][j] == 0 && g[i+2][j] == 2 && g[i+3][j] == 0) ans++;
//每行和每列最多走到第297行、297列,后面还有三行、三列,是最右下边的2020
if(j <= 297 && i <= 297 && g[i][j] == 2 && g[i+1][j+1] == 0 && g[i+2][j+2] == 2 && g[i+3][j+3] == 0) ans++;
}
}
System.out.println(ans);
}
}
题C:蛇形填数【10分】
【题目描述】
如下图所示,小明用从1 开始的正整数“蛇形”填充无限大的矩阵。
容易看出矩阵第二行第二列中的数是5。请你计算矩阵中第20 行第20 列的数是多少?
【答案】761
【题解】从矩阵中可以发现每当在第一行时就向右边移动一位在往左下方递增,当在第一列时就向下移动一位再往右上方递增,当遍历到了第20行20列就输出答案结束遍历。另外由于遍历到第三行时最大需要填充2*3-1 = 5行,故遍历到第20行时,最大需要填充到39行,所以我们需要至少开39行39列的数组。我开了50。
代码:
import java.util.Scanner;
public class Main {
static int g[][] = new int[50][50];
public static void main(String[] args) {
g[1][1] = 1;//第一个值直接给出
int x = 1,y = 2;//从第一行第二列开始往左下方递增
int cnt = 1;//记录值
while(x != 20 || y != 20) {//当没有到第20行20列时就继续执行
while(y >= 1) {//右上到左下
g[x][y] = ++cnt;//赋值
if(x == y && y == 20) {//遍历到就输出结果,结束遍历
System.out.println(g[x][y]);
return;
}
x++;y--;//左下:下一行,前一列
}
y++;//y到了第0列时会从while循环中出来,这时需要将y加1到第一列的位置
while(x >= 1) {//从左下到右上
g[x][y] = ++cnt;//赋值
if(x == y && y == 20) {//遍历到就输出结果,结束遍历
System.out.println(g[x][y]);
return;
}
x--;y++;//右上:上一行,后一列
}
x++;//x到了第0行时会从while循环中出来,这时需要将x加1到第一行的位置
}
}
}
题D:七段码【10分】
【题目描述】
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有7 段可以发光的二极管,分别标记为a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
【答案】80
【题解】一共有7个字母,每个字母有选和不选两种情况,一共有2^7=128种情况。但是还有一个条件:所有发光的二极管是连成一片的。首先我们可以将每个字母和其他哪些字母直接相连的记录下来。然后我们可以用dfs先将每种情况枚举出来,再写一个dfs判断这种情况下能否走完所有发光的二极管,如果可以则满足条件,答案加1,否则不行。
代码:
import java.util.Arrays;
import java.util.LinkedList;
public class Main {
static int INF = 0x3f3f3f3f,ans = 0;
static int a[] = new int[10];//每个二极管是亮还是不亮
static int b[] = new int[10];//是否和其他发光二极管连通
static int g[][] = new int[10][10];//制图
static void dfs1(int x) {
if(x == 7){//每个位置都有了结果(选或不选)
//初始化数组
Arrays.fill(b, 0);
int flag = 0,flg = 0;//flag表示是否有未连通的发光二极管,flg表示是否是第一次进入
for(int i = 0; i < 7; i++) {
if(a[i] == 1 && flg == 0) {
flg = 1;
b[i] = 1;
dfs2(i,a);
}
}
for (int i = 0; i < 7; i++) {
if(a[i] == 1 && b[i] == 0) {//如果没有标记,则不连通
flag = 1;
break;
}
}
if(flag == 0) ans++;
return;
}
// 每个位置有选和不选两种情况
a[x] = 1;
dfs1(x+1);
a[x] = 0;
dfs1(x+1);
}
static void dfs2(int x,int c[]) {//将所有连通的二极管标记
for(int i = 0; i < 7; i++) {
if(i == x) continue;
if(g[x][i] == 1 && c[i] == 1 && b[i] != 1) {
b[i] = 1;
dfs2(i, c);
}
}
}
public static void main(String[] args) {
// 将每个字母和哪些字母直接相连记录一下
for(int i = 0; i < 7; i++) Arrays.fill(g[i], INF);
g[0][1] = g[1][0] = 1;
g[0][5] = g[5][0] = 1;
g[1][2] = g[2][1] = 1;
g[1][6] = g[6][1] = 1;
g[2][6] = g[6][2] = 1;
g[2][3] = g[3][2] = 1;
g[3][4] = g[4][3] = 1;
g[4][5] = g[5][4] = 1;
g[4][6] = g[6][4] = 1;
g[5][6] = g[6][5] = 1;
dfs1(0);
System.out.println(ans-1);//减去全灭的那种情况
}
}
E题:排序【15分】
【题目描述】
小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。
在冒泡排序中,每次只能交换相邻的两个元素。
小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串lan 排序,只需要1 次交换。对于字符串qiao 排序,总共需要4 次交换。
小蓝找到了很多字符串试图排序,他恰巧碰到一个字符串,需要100 次交换,可是他忘了吧这个字符串记下来,现在找不到了。
请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对该串的字符排序,正好需要100 次交换。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。
【答案】jonmlkihgfedcba
【题解】只包含小写英文字母且没有字母重复出现的字符串,一共只有26个字母,需要交换100次,可以通过遍历得到需要15个字母。最多可以交换105次,这里只要交换100次,需要找到最短和字典序最小的那个。我们可以将交换5次的字母提到最前面即可减少5次的交换,并且字典序为最小,不难得知需要交换五次的字母为第六个的j.
代码:
public class Main {
public static void main(String[] args) {
// int sum = 0,k = 0;
// for (int i = 1; i <= 26; i++) {
// sum += i;
// if(sum >= 100) {
// k = i;
// break;
// }
// }
// System.out.println(k+" "+sum);//14 105,需要15个字母,从第1个位置到15需要转换14次
System.out.println("jonmlkihgfedcba");
}
}
题F:成绩分析【15分】
【题目描述】
小蓝给学生们组织了一场考试,卷面总分为100 分,每个学生的得分都是一个0 到100 的整数。
请计算这次考试的最高分、最低分和平均分。
【输入格式】
输入的第一行包含一个整数n,表示考试人数。
接下来n 行,每行包含一个0 至100 的整数,表示一个学生的得分。
对于50% 的评测用例,1 ≦ n ≦ 100。
对于所有评测用例,1 ≦ n ≦ 10000。
【输出格式】
输出三行。
第一行包含一个整数,表示最高分。
第二行包含一个整数,表示最低分。
第三行包含一个实数,四舍五入保留正好两位小数,表示平均分。【输入样例 】
7 80 92 56 74 88 99 10
【输出样例 】
99 10 71.29
【题解】在输入数组时可同时将最大值、最小值和总和记录下来,然后让总和除以数组个数并保留两位小数。
代码:
import java.util.Scanner;
public class Main {
static int N = 100010;
static int a[] = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int max = 0,min = 100;
double sum = 0.0;
for(int i = 1; i <= n; i++) {
a[i] = sc.nextInt();
max = Math.max(max, a[i]);
min = Math.min(min, a[i]);
sum += a[i];
}
System.out.println(max);
System.out.println(min);
System.out.printf("%.2f",sum/n);
}
}
题G:单词分析【20分】
【题目描述】
小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。
【输入格式】
输入一行包含一个单词,单词只由小写英文字母组成。
对于所有的评测用例,输入的单词长度不超过1000。【输出格式】
输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪个。
如果有多个字母出现的次数相等,输出字典序最小的那个。【输入样例 】
样例1: lanqiao 样例2: longlonglongistoolong
【输出样例 】
样例1: a 2 样例2: o 6
【题解】记录字符串中每个字母的出现次数,输出出现最多的那个字母和出现次数即可。
代码:
import java.util.Scanner;
public class Main {
static int zm[] = new int[26];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
zm[ch - 'a']++;
}
int cnt = 0;
char ch = 'a';
for(int i = 0; i < 26; i++) {
if(cnt < zm[i]) {
cnt = zm[i];
ch = (char)('a' + i);
}
}
System.out.println(ch);
System.out.println(cnt);
}
}
题H:数字三角形【20分】
【题目描述】
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。
对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。
此外,向左下走的次数与向右下走的次数相差不能超过1。
【输入格式】
输入的第一行包含一个整数N (1 < N ≤ 100),表示三角形的行数。
下面的N 行给出数字三角形。数字三角形上的数都是0 至100 之间的整数。【输出格式】
输出一个整数,表示答案。
【输入样例】
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
【输出样例】
27
【题解】简单的dp题,先用一个数组将数字三角形保存下来,因为路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数,然后再新建一个数组记录左上或右上的最大值加自己本身。很巧妙的一点就是向左下走的次数与向右下走的次数相差不能超过1这个条件,因为你拿图试着走几遍就会发现其实如论哪种方法最后都会走到最后一行的最中间的那个位置。
代码:
import java.util.Scanner;
public class Main {
static int N = 110;
static int g[][] = new int[N][N];
static int dp[][] = new int[N][N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= i; j++) {
g[i][j] = sc.nextInt();
}
}
dp[1][1] = g[1][1];
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= i; j++) {
dp[i][j] = Math.max(dp[i-1][j]+g[i][j], dp[i-1][j-1]+g[i][j]);
// System.out.print(dp[i][j]+" ");
}
// System.out.println();
}
if(n % 2 != 0) System.out.println(dp[n][n/2+1]);
else System.out.println(Math.max(dp[n][n/2], dp[n][n/2+1]));
}
}
更新中。。。