2020年
注:完全不会的,没写入其中
门牌制作
题目描述
小蓝要为一条街的住户制作门牌号。
这条街一共有2020 位住户,门牌号从1 到2020 编号。
小蓝制作门牌的方法是先制作0 到9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌1017 需要依次粘贴字符1、0、1、7,即需要1 个字符0,2 个字符1,1 个字符7。
请问要制作所有的1 到2020 号门牌,总共需要多少个字符2?
输出格式
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。
这是道简单题,暴力枚举即可
public class Main {
public static void main(String[] args) {
int n = 2020;
int cnt = 0;
for(int i = 1; i <= n;i++) {
String str = i + "";
if(str.contains("2")) {
int a = i;
int b = a;
// System.out.println(i);
while(a != 0) {
b = a % 10;
a /= 10;
if(b == 2) cnt++;
}
}
}
System.out.println(cnt);
// 测试
// int x = 2021;
// int a = x;
// int b = a;
// while(a != 0) {
// b = a % 10;
// a /=10;
// System.out.println(a + " " + b);
// }
}
}
答案为:624
蛇形填数
题目描述
如下图所示,小明用从1 开始的正整数“蛇形”填充无限大的矩阵。
容易看出矩阵第二行第二列中的数是5。请你计算矩阵中第20 行第20 列的数是多少?
输出格式
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。
这里既可以手写模拟,也可以通过编程实现。这里我就使用编程来实现。
//本质上是找规律,可以手写模拟即可
public class Main {
static int N = 100;
static int[][] a = new int[N][N];
public static void main(String[] args) {
int cnt = 1;
int k = 0;
int i = 0,j = 0;
while(k <= 60) {
if(i == 0 && j == 0) {a[i][j] = cnt++;j++;}
else if(i == 0) {
while(j > 0) {
a[i][j] = cnt++;
i++;
j--;
}
a[i][j] = cnt++;
i++;
}else if(j == 0) {
while(i > 0) {
a[i][j] = cnt++;
i--;
j++;
}
a[i][j] = cnt++;
j++;
}
k++;
}
System.out.println(a[19][19]);
// 测试
// int x = 0;
// a[0][0] = x++;
// System.out.println(a[0][0]);
}
}
七段码
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有7 段可以发光的二极管,分别标记为a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
输出格式
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。
这道题并不会做,看网上的题解是通过并查集来解决。(看完还是不会。。。)
这道题第一反应就是要dfs,但是对于我们暴力枚举完每一种灯光暗的方式之后,我们要如何判断他们不相邻的问题呢,而此时的连通判断就是要使用到并查集(之前学并查集的时候,只知道是合并和查找会很快,但很少用到,不知道用途)。
边转换成点之后改成了图的形式
解题步骤:
首先要写出dfs代码
模板:
//核心代码
public static void dfs(int u) {
//结束时的情况,应当怎么处理
//遍历每一种情况
//筛选掉不合理的情况
//合法情况,走向下一步,进行标记
//dfs(u + 1)
//回溯
}
根据上面,我们就可以编写了
//并查集,并不会
public class Main {
// 这里我们将灯之间的联系转换为图
static int N = 10;
static int[] mp = new int[N];
static int res;
static int[][] g = new int[N][N]; //存储当前灯的联系
static int[] fa = new int[N * N];
//并查集核心代码
public static int find(int x) {
if(fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
//将b接到a节点上
public static void merge(int a,int b) {
fa[find(a)]=find(b);
}
//初始化一下
public static void init() {
for(int i=0;i<100;i++){
fa[i]=i;
}
}
public static void dfs(int u) {
//结束时的情况,应当怎么处理
if(u >= 7) {
//这个比较难想
//现在是所有情况已经枚举出来了.就是寻找联系的时候了
for(int i = 0; i < 7;i++) {
//如果当前灯亮
if(mp[i] == 1) {
for(int j = 0; j < 7;j++) {
if(g[i][j] == 1 &&mp[j] == 1) { //如果此时g[i][j](也就是i灯和j灯之间有连接且j灯刚好亮)
merge(i,j);//将j接到i上
}
}
}
}
int t = -1;
int m = 0;
for(m = 0; m < 7; m++) {
if(mp[m] == 1 && t == -1) t = find(m);//首先找到m的祖宗节点
if(mp[m] == 1 && find(m) != t) break; //如果m的祖宗节点跟t不相等,说明它们是不连接的,所以不符合
}
if(m==7&&t!=-1) res++; //注意全灭的情况
init();
return;
}
//遍历每一种情况
//筛选掉不合理的情况
//合法情况,走向下一步,进行标记
//dfs(u + 1)
//回溯
//当前灯亮
mp[u] = 0;
dfs(u + 1);
//当前灯不亮
mp[u] = 1;
dfs(u + 1);
}
public static void main(String[] args) {
//自己对自己肯定是1
for(int i=0;i<7;i++){
g[i][i]=1;
}
//现在是连接关系
g[0][1]=g[1][0]=g[0][2]=g[2][0]=1;
g[1][3]=g[3][1]=g[1][4]=g[4][1]=1;
g[2][3]=g[3][2]=g[2][5]=g[5][2]=1;
g[3][4]=g[4][3]=g[3][5]=g[5][3]=1;
g[4][6]=g[6][4]=1;
g[5][6]=g[6][5]=1;
init();
dfs(0);
System.out.println(res);
}
}
寻找2020
题目描述
小蓝有一个数字矩阵,里面只包含数字0 和2。小蓝很喜欢2020,他想找到这个数字矩阵中有多少个2020 。
小蓝只关注三种构成2020 的方式:
- 同一行里面连续四个字符从左到右构成2020。
- 同一列里面连续四个字符从上到下构成2020。
- 在一条从左上到右下的斜线上连续四个字符,从左上到右下构成2020。
例如,对于下面的矩阵:
220000
000000
002202
000000
000022
002020
一共有5 个2020。其中1 个是在同一行里的,1 个是在同一列里的,3 个是斜线上的。 小蓝的矩阵比上面的矩阵要大,由于太大了,他只好将这个矩阵放在了一个文件里面。
在本试题中有一个文件2020.txt,里面给出了小蓝的矩阵。
请帮助小蓝确定在他的矩阵中有多少个2020。
这是一道结果填空的题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
本题比较简单,可能难点在读取文件上,记住就好了,这道题暴力就行,没啥好说的
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
public class Main {
static int N = 510;
static int[][] a = new int[N][N];
static int cnt = 0;
static int m = 0;
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
BufferedReader br = new BufferedReader(new FileReader("src/寻找2020/2020.txt"));
String s;
while((s=br.readLine()) != null){
String t = s;
m = t.length();
for(int i = 0; i < t.length();i++) {
a[cnt][i] = t.charAt(i) - '0';
}
cnt++;
}
int res = 0;
for(int i = 0; i < cnt;i++) {
for(int j = 0; j < m;j++) {
//横向
if(i + 3 < cnt &&a[i][j] == 2 && a[i + 1][j] == 0 && a[i + 2][j] == 2 && a[i + 3][j] == 0) {
res++;
}
//竖向
if(j + 3 < m &&a[i][j] == 2 && a[i][j + 1] == 0 && a[i][j + 2] == 2 && a[i][j + 3] == 0) {
res++;
}
//斜向
if(i + 3 < cnt && j + 3 < m &&a[i][j] == 2 && a[i + 1][j + 1] == 0 && a[i + 2][j + 2] == 2 && a[i + 3][j + 3] == 0 ) {
res++;
}
}
}
System.out.println(res);
br.close();
}
}
排序
不会,结束
成绩分析
题目描述
小蓝给学生们组织了一场考试,卷面总分为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 = 10010;
static int[] a = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
int sum = 0;
for(int i = 0; i < n;i++) {
a[i] = sc.nextInt();
if(a[i] > max) max = a[i];
if(a[i] < min) min = a[i];
sum +=a[i];
}
System.out.println(max);
System.out.println(min);
double t = sum / n;
double s = t * 1000;
if(s % 10 >= 5) System.out.printf("%.2f",1.0 * sum / n + 0.01);
else System.out.printf("%.2f",1.0 * sum / n);
}
}
子串分值和
题目描述
对于一个字符串S ,我们定义S 的分值f (S ) 为S 中出现的不同的字符个数。
例如f (”aba”) = 2, f (”abc”) = 3, f (”aaa”) = 1。
现在给定一个字符串S [0 : n - 1](长度为n),请你计算对于所有S 的非空子串S [i : j](0 ≤ i ≤ j < n), f (S [i:: j]) 的和是多少。
输入格式
输入一行包含一个由小写字母组成的字符串S 。
对于所有评测用例,1 ≤ n ≤ 100000。
输出格式
输出一个整数表示答案。
输入样例 复制
ababc
输出样例 复制
28
一道动态规划题,偶不会,看题解过来的
首先是暴力解法,暴力解法的时间复杂度是O( n 2 n^{2} n2),而这道题数据是10万,故一定会超时
暴力解法就是枚举字符串每个字符,对于每个字符,向前枚举以当前字符结尾的子串,计算分值,然后累加。
代码:
import java.util.Arrays;
import java.util.Scanner;
/**
* 暴力
* @author linkora
*
*/
public class Main {
static int N = 100010;
static boolean[] st = new boolean[N];
static char[] str = new char[26];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
long ans = 0;
for(int i = 0; i < s.length();i++) {
Arrays.fill(st, false);
int t = s.charAt(i) - 'a';
st[t] = true;
long cnt = 1;
ans+=cnt;
for(int j = i - 1; j >= 0;j--) {
t = s.charAt(j) - 'a';
if(!st[t]) {
cnt++;
st[t] = true;
}
ans+=cnt;
}
}
System.out.println(ans);
}
}
接下来就是优化的问题了,首先我们要知道暴力是每次都要重新去遍历前面的子串,那么我们能不能优化下前面的步骤呢。
首先我们来看设以当前字符结尾的所有子串的分值为f[i],现在我们来看看f[i]和f[i - 1]的关系
从图中我们可以看出,f[i]与f[i - 1]的关系就是多添加了s[i],也就是说我们要知道对于f[i - 1]来说.在字符串结尾添加s[i]对f[i - 1]的影响,也就是贡献值。
第ii个新增元素s[i]定会有子集s[i], 故产生贡献值为1
则问题转化为求解加入一个字符s[i]后对前面i−1个子串产生的影响,即可以看成是s[i]的贡献值
由于s[i]可以影响到它前面连续的不等同于s[i]的串的分值,并且每个子串的分值至多+1
故可以通过记录每个字符最后出现的位置pos,这里解释下就是当你知道与s[i]相同的字符s[j]后,从s[j]往前的子串,s[i]是并没有贡献值的,因为s[j]之前已经被s[j]记录过一次了。
则多出s[i]后比f[i−1]多产生的分数就是i − 1 − pos
故f[i]=f[i−1]+i−pos
遍历字符串O(n), 状态转移O(1), 总的时间复杂度O(n)
代码:
import java.util.Scanner;
public class Main01 {
static int N = 100010;
static int[] f = new int[N];
static char[] s = new char[N];
static int[] pos = new int[26];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
for(int i = 1; i <= str.length();i++) {
s[i] = str.charAt(i - 1);
}
long ans = 0;
for(int i = 1; i <= str.length();i++) {
int t = s[i] - 'a';
f[i] = f[i - 1] + i - pos[t];
pos[t] = i;
ans += f[i];
}
System.out.println(ans);
}
}
单词分析
题目描述
小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。
输入格式
输入一行包含一个单词,单词只由小写英文字母组成。
对于所有的评测用例,输入的单词长度不超过1000。
输出格式
输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪个。
如果有多个字母出现的次数相等,输出字典序最小的那个。
输入样例 复制
样例1:
lanqiao
样例2:
longlonglongistoolong
输出样例 复制
样例1:
a
2
样例2:
o
6
简单的模拟题,枚举就可以了
import java.util.Scanner;
public class Main {
static int N = 30;
static int[] a = new int[N];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
for(int i = 0; i < s.length();i++) {
a[s.charAt(i) - 'a']++;
}
int max = -1;
char t = ' ';
for(int i = 0; i < a.length;i++) {
if(a[i] > max) {
max = a[i];
t = (char)(i + 'a');
}
}
System.out.println(t);
System.out.println(max);
}
}
数字三角形
题目描述
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。
对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。
此外,向左下走的次数与向右下走的次数相差不能超过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
一道经典动态规划题,这道题相对于原题的话是多了一个条件,也就是向左下走的次数与向右下走的次数相差不能超过1
按照往常来说,会让你求出最大的和。
这时候只需要求出最后的和即可,这道题我没做出来主要还是没想到,如果左边和右边相差的次数不超过1的话,那就说明最后一步是只能在中间的。
import java.util.Scanner;
public class Main {
static int N = 110;
static int[][] a = new int[N][N];
static int INF = (int)1e8;
static int[][] f = 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++) {
a[i][j] = sc.nextInt();
}
}
//初始化最小值
for(int i = 0; i <= n;i++) {
for(int j = 0; j <= i + 1;j++) {
f[i][j] = -INF;
}
}
f[1][1] = a[1][1];
for(int i = 2; i <= n;i++) {
for(int j = 1; j <= i;j++) {
f[i][j] = Math.max(f[i - 1][j], f[i - 1][j - 1]) + a[i][j];
}
}
if(n % 2 == 0) {
System.out.println(Math.max(f[n][n / 2], f[n][n / 2 + 1]));
}
else{
System.out.println(f[n][n / 2 + 1]);
}
}
}