目录
试题A :约数个数
答案:96
思路:简单枚举,注意1和本身也算约数。
public class Main {
public static void main(String[] args) {
int ans = 0 ;
for(int i=1; i<=78120; i++){
if(78120%i==0){
ans ++ ;
}
}
System.out.println(ans);
}
}
试题B:跑步锻炼
答案:8879
思路:Java日期时间API的应用,根据平年和闰年,算出总天数days,算出周一的天数a,算出初一的天数b,再算出既是初一又是周一的天数ans,那么最终的跑步路程为(days-(a+b-ans)) + (a+b-ans)*2。
import java.util.Calendar;
import static java.time.Year.isLeap;
public class Main {
public static void main(String[] args) {
Calendar c = Calendar.getInstance() ;
int years = 2000;
int same = 0 ;
//Calendar的月份是从0到11的,不是1到12,需要注意,谨慎一点,时间API也是常考的
c.set(years,0, 1) ;
while(c.get(Calendar.YEAR) != 2020 || c.get(Calendar.MONTH) != 9 || c.get(Calendar.DATE) != 1){
//从2000年1月1日开始判断,每次判断一个月的第一天,如果是周一,就用same记录
int weekday = c.get(Calendar.DAY_OF_WEEK) - 1 ;
if(weekday==1){
same ++ ;
}
if(c.get(Calendar.MONTH)<11){
c.set(Calendar.MONTH, c.get(Calendar.MONTH)+1) ;
}else{
years ++ ;
c.set(Calendar.YEAR, years);
c.set(Calendar.MONTH, 0);
}
}
long days = 0 ;
for(int year=2000; year<=2020; year++){
if(isLeap(year)){
days += 366 ;
}else{
days += 365 ;
}
}
days = days - 31 - 30 - 30 ;
long a = (days-6) / 7 + 1; //星期1
long b = 12*20 + 10 ; //初一
long ans = days - (a+b-same) ;
System.out.println(2*(a+b-same)+ans);
}
}
试题C:平面分割
答案:1391
思路:没有思路,哈哈,我看别人的思路是让尽可能的相交,这样产生的区域就越多,至于具体怎么推导的,可以看下这个。参考链接:蓝桥杯试题E: 平面分割 - riz9 - 博客园
试题D:蛇形填数
答案:761
思路:模拟斜对角向上和向下填数过程即可。
//试题D-蛇形填数
public class Main {
public static void main(String[] args) {
int row = 0, col = 0 ;
int num = 0 ;
while(true){
num ++ ;
if(row==19 && col ==19){
break ;
}
if((row+col)%2==0){ //向上走
if(row==0){
col ++ ;
}else{
row -- ;
col ++ ;
}
}else{ //向下走
if(col==0){
row ++ ;
}else{
row ++ ;
col -- ;
}
}
}
System.out.println(num);
}
}
试题E:排序
答案:jonmlkihgfedcba
相邻交换100次,最短需要15个字符,正常前15个字符逆序,交换1+2+3+...+14=105次,故把j放到首位,交换100次,最短并且字典序最小。
public class Main {
public static void main(String[] args) {
int ans = 0 ;
//前15个小写字母逆序,执行105交换,此时是最短的,要保证字典序最小,把第5个移动到首位
System.out.println("jonmlkihgfedcba");
}
}
试题F:成绩统计
思路:枚举,计算即可,注意四舍五入。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
int n =input.nextInt() ;
int pass = 0, excellent = 0 ;
for(int i=0; i<n; i++){
int grade = input.nextInt() ;
if(grade>=85){
excellent ++ ;
}
if(grade>=60){
pass++ ;
}
}
int ans1, ans2 ;
double x = 1.0 * pass / n * 1000;
double y = 1.0 * excellent / n * 1000 ;
if(x==1000){
System.out.println(100 + "%");
}else {
String s1 = String.valueOf(x);
int c1 = s1.charAt(2) - '0';
if (c1 >= 5) {
ans1 = Integer.parseInt(s1.substring(0, 2)) + 1;
} else {
ans1 = Integer.parseInt(s1.substring(0, 2));
}
System.out.println(ans1 + "%");
}
if(y==1000){
System.out.println(100 + "%");
}else {
String s2 = String.valueOf(y);
int c2 = s2.charAt(2) - '0';
if (c2 >= 5) {
ans2 = Integer.parseInt(s2.substring(0, 2)) + 1;
} else {
ans2 = Integer.parseInt(s2.substring(0, 2));
}
System.out.println(ans2 + "%");
}
}
}
试题G:回文日期
思路:枚举N+1天开始的所有日期,判断是否满足条件即可。细节很多,需要注意处理细节。
import java.util.Scanner;
import static java.time.Year.isLeap ;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
int N = input.nextInt() ;
for(int i=N+1;i<=99991231;i++){
int d = i % 100 ;
if(d>31){
i += 68 ;
}
if(i%10000>=13000){
i += i / 10000 + 999 ;
}
if(f1(i)){
System.out.println(i);
break ;
}
}
for(int i=N+1;i<=99991231; i++){
int d = i % 100 ;
if(d>31){
i += 68 ;
}
if(i%10000>=13000){
i += i / 10000 + 999;
}
if(f1(i) && f2(i)){
System.out.println(i);
break ;
}
}
}
public static boolean f1(int i){
String s = String.valueOf(i) ;
int month = Integer.parseInt(s.substring(4,6)) ;
int day = Integer.parseInt(s.substring(6,8)) ;
if(month==0 || day==0){
return false ;
}
if(month>12 || day>31){
return false ;
}
if(month==4 || month==6 || month==9 || month==11 ){
if(day>30){
return false ;
}
}
if(isLeap(Integer.parseInt(s.substring(0,4)))){
if(day>29){
return false ;
}
}else{
if(day>28){
return false ;
}
}
if(!isPalindrome(s)){
return false ;
}
return true ;
}
private static boolean isPalindrome(String s) {
for(int i=0; i<s.length(); i++){
if(s.charAt(i) != s.charAt(s.length()-1-i)){
return false ;
}
}
return true ;
}
public static boolean f2(int i){
String s = String.valueOf(i) ;
if(s.charAt(0)==s.charAt(2) && s.charAt(2) == s.charAt(5) && s.charAt(7)==s.charAt(5)){
if(s.charAt(1)==s.charAt(3) && s.charAt(3) == s.charAt(4) && s.charAt(4)==s.charAt(6)){
if(s.charAt(0) != s.charAt(1)){
return true ;
}
}
}
return false ;
}
}
试题H:作物杂交
思路:记忆化搜索,ans数组记忆已经得到的结果,vis数组标记当前作物是否已经生成,如果目标种子没有合成,遍历当前所有已有的杂交组合,对于合成值等于target的,递归计算两个合成target值得种子分别合成所需要得最大值。求出所有可能得最小值即是答案。AC代码如下:
import java.util.Scanner;
public class Main {
static int N, M, K, T ;
static int [][] hby ;
static int [] time ;
static int [] seed ;
static int [] maxTime ;
static int [] vis ;
static int [] ans ;
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
N = input.nextInt() ;
M = input.nextInt() ;
K = input.nextInt() ;
T = input.nextInt() ;
time = new int [N+1] ;
seed = new int [M] ;
hby = new int [K][3] ;
maxTime = new int [K] ; //记录两两杂交的最大时间
vis = new int [N+1] ;
ans = new int [N+1] ;
for(int i=1; i<=N; i++){
time[i] = input.nextInt() ;
}
for(int i=0; i<M; i++){
seed[i] = input.nextInt() ;
vis[seed[i]] = 1 ; //记录作物已经合成
}
for(int i=0; i<K; i++){
hby[i][0] = input.nextInt() ;
hby[i][1] = input.nextInt() ;
hby[i][2] = input.nextInt() ;
maxTime[i] = Math.max(time[hby[i][0]], time[hby[i][1]]) ;
}
System.out.println(dfs(T));
}
private static int dfs(int target) {
if(vis[target]!=1){
int min = Integer.MAX_VALUE ;
for(int i=0; i<K; i++){
if(hby[i][2]==target){
min = Math.min(min, maxTime[i] + Math.max(dfs(hby[i][0]), dfs(hby[i][1]))) ;
}
}
vis[target] = 1 ;
ans[target] = min ;
return min ;
}else{
return ans[target] ;
}
}
}
试题I:子串分值
思路1:枚举+HashMap记录,枚举所有可能,Map记录每个出现1次的字符,统计个数。可以通过部分测试用例,拿到10分+没问题。
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
String s = input.next() ;
long ans = 0 ;
for(int i=0; i<s.length(); i++){
for(int j=i+1; j<=s.length(); j++){
ans += f(s.substring(i,j));
}
}
System.out.println(ans);
}
public static long f(String s){
long sum = 0 ;
Map<Character, Integer> map = new HashMap<>() ;
for(int i=0; i<s.length(); i++){
map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1) ;
}
for(char c : map.keySet()){
if(map.get(c)==1){
sum ++ ;
}
}
return sum ;
}
}
思路2:AC代码,动态规划思想,dp[i]表示以i结尾的字符串中的每个字符的贡献值,place数组记录每个字符上一次出现的位置,ans记录当前字符的贡献值,sum为所有字符的贡献值,每一次更新dp[c]和place[c].
import java.util.*;
public class Main1 {
static int ans, sum ;
static int [] dp ;
static int [] place ;
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
String s = input.next() ;
dp = new int [26] ; //dp[i]表示以i结尾的字符串中每个字符的贡献值
place = new int [26] ; //记录每个字符出现的位置
Arrays.fill(place, -1) ;
for(int i=0; i<s.length(); i++){
int c = s.charAt(i) - 'a' ;
ans += i - place[c] - dp[c] ;
sum += ans ;
dp[c] = i - place[c] ;
place[c] = i ;
}
System.out.println(sum);
}
}