第九届蓝桥杯JavaA组(2018年)省赛真题解析
1.分数
- 1/1+1/2+1/4+1/8+1/16+…
- 每项是前一项的一半,如果一共有20项,求这个和是多少
- 结果用分数表示,类似:
- 3/2,当然这这是加了前2项而已,分子分母要求互质,
- 提交的是已经约分过的分数。
思想:求出分子分母,同除最大公约数即可。
/**
* 1.分数
* 1/1+1/2+1/4+1/8+1/16+...
* 每项是前一项的一半,如果一共有20项,求这个和是多少
* 结果用分数表示,类似:
* 3/2,当然这这是加了前2项而已,分子分母要求互质,
* 提交的是已经约分过的分数。
*/
public class Main {
static int n ;
public static void main(String[] args) {
int index = 1, sum = 0 ;
for(int i=1; index<=20; i*= 2){
n = i ;
sum += i ;
index ++ ;
}
System.out.println(sum/gcd(sum,n) + "/" + n/gcd(sum,n));
}
private static int gcd(int sum, int n) {
if(n==0){
return sum ;
}
return gcd(n, sum%n) ;
}
}
2.星期一
思想:做个平闰年判断,累积天数,然后除以7就是星期一的天数。
import static java.time.Year.isLeap;
public class Main1 {
public static void main(String[] args) {
long days = 0 ;
for(int year=1901; year<=2000; year++){
if(isLeap(year)){
days += 366 ;
}else{
days += 365 ;
}
}
System.out.println(days/7);
}
/**
private static boolean leap(int year){
if((year%4 == 0 && year%100!=0) || year%400==0){
return true ;
}
return false ;
}
*/
}
3.复数幂
思想:这个需要用到Java特有的BigInteger,然后迭代找出虚部和实部即可。
import java.math.BigInteger;
/**
* 3.复数幂
* 设i为虚数单位,对任意正整数n,(2+3i)^n的实部和虚部都是整数,
* 求(2+3i)^123456等于多少,这个数字很大,要求精确表示,
*/
public class Main {
static BigInteger aa, bb ;
public static void main(String[] args) {
BigInteger a = new BigInteger("2") ;
BigInteger b = new BigInteger("3") ;
aa = null;
bb = null ;
for(int i=1; i<=123455; i++){
aa = a.multiply(new BigInteger("2")).subtract(b.multiply(new BigInteger("3"))) ;
bb = b.multiply(new BigInteger("2")).add(a.multiply(new BigInteger("3"))) ;
a = aa ;
b = bb ;
}
System.out.println(a + "" + (b.compareTo(BigInteger.ONE)<=0 ? "" : "+") + b + "i");
}
}
4.方格计数
思想:求出一个象限满足限制条件的,乘以4即可。
public class Main {
public static void main(String[] args) {
long ans = 0 ;
long N = 50000;
long y = N ;
for(long x=1; x<=N; x++){
while(y>0 && x*x+y*y>N*N){
y -- ;
}
ans += y ;
}
System.out.println(4*ans);
}
}
5.代码填空:略
6.航班日期
思想:规律题,两次航行的时间差求和取平均就是航行时间。
/**
* 航班日期
3
17:48:19 21:57:24
11:05:18 15:14:23
17:21:07 00:31:46 (+1)
23:02:41 16:13:20 (+1)
10:19:19 20:41:24
22:19:04 16:41:09 (+1)
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Main1 {
static int T ;
static Scanner input = new Scanner(System.in) ;
public static void main(String[] args) throws ParseException {
T = input.nextInt() ;
input.nextLine() ;
for(int i=0; i<T; i++){
long t1 = getTime() ;
long t2 = getTime() ;
long t = (t1+t2) / 2 ;
System.out.printf("%02d:%02d:%02d\n",t/3600,t/60%60, t%60);
}
}
private static long getTime() throws ParseException {
String time = input.nextLine() ;
String [] split = time.split(" ") ;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss") ;
Date t1 = simpleDateFormat.parse(split[0]) ;
Date t2 = simpleDateFormat.parse(split[1]) ;
int d = 0 ;
if(split.length==3){
d = Integer.parseInt(split[2].substring(2,3)) ;
}
return d*24*3600 + t2.getTime()/1000 - t1.getTime()/1000 ;
}
}
7.三体攻击
思想:这题比较,我用的是暴力法,可以通过部分测试用例,比较好的方法是二分加三维前缀和,但是赛场上还是用暴力迅速得分靠谱。
import java.util.Scanner;
/**
* 7.三体攻击
*
*/
public class Main {
static int A,B,C,m ;
static int [][] attack ;
static int [][][] a ;
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
A = input.nextInt() ;
B = input.nextInt() ;
C = input.nextInt() ;
m = input.nextInt() ;
a = new int [A+1][B+1][C+1] ; //用来存储每个战舰的生命值
attack = new int [m][7] ;//记录每一轮攻击的7个数据
for(int i=1; i<=A; i++){ //记录战舰的生命值
for(int j=1; j<=B; j++){
for(int k=1; k<=C; k++){
a[i][j][k] = input.nextInt();
}
}
}
for(int i=0; i<m; i++){ //记录攻击信息
for(int j=0; j<7; j++){
attack[i][j] = input.nextInt() ;
}
}
for(int round=0; round<m; round++){ //攻击轮数
for(int i=attack[round][0]; i<=attack[round][1]; i++){
for(int j=attack[round][2]; j<=attack[round][3]; j++){
for(int k=attack[round][4]; k<=attack[round][5]; k++){
if(a[i][j][k] > 0){ //受到攻击生命值减少
a[i][j][k] -= attack[round][6] ;
}else{ //生命值小于0,爆炸
System.out.println(round+1);
return ;
}
}
}
}
}
}
}
8.全球变暖
思想:搜索+标记
第一轮搜索算出有多少岛屿 ;
然后迭代遍历将不会被淹没的标记出来
第二轮搜出出不会被淹没的岛屿数量
两轮搜索的结果相减就是被淹没的岛屿数量
import java.util.Scanner;
/**
* 8.全球变暖
*/
/**
7
.......
.##....
.##....
....##.
..####.
...###.
.......
*/
public class Main {
static char [][] a ;
static int N ;
static int cnt = 0, cnt1 ;
static int [] offsetX = {-1,1,0,0} ;
static int [] offsetY = {0,0,-1,1} ;
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
N = input.nextInt() ;
a = new char [N][N] ;
String s = "" ;
int index = 0 ;
for(int i =0; i<N; i++){
s += input.next() ;
}
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
a[i][j] += s.charAt(index++) ;
}
}
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(a[i][j] == '#') {
dfs1(a, i, j);
cnt ++ ;//计算岛屿数量
}
}
}
for(int i=1; i<N-1; i++) { //还没被淹没的标记为#
for (int j = 1; j < N-1; j++) {
if(a[i][j] == '1' && a[i-1][j] == '1' && a[i+1][j]=='1' && a[i][j-1]=='1' && a[i][j+1]=='1'){
a[i][j] = '#' ;
}
}
}
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
if(a[i][j] == '#') {
dfs1(a, i, j);
cnt1 ++ ;//计算未被淹没的岛屿数量
}
}
}
System.out.println(cnt-cnt1); //被淹没的岛屿数量
}
private static void dfs1(char[][] a, int x, int y) {
a[x][y] = '1' ;
for(int i=0; i<4; i++){
int nx = x + offsetX[i] ;
int ny = y + offsetY[i] ;
if(nx<0 || ny<0 || nx>N || ny>N){
continue;
}
if(a[nx][ny] == '#')
dfs1(a, nx, ny) ;
}
}
}
9.倍数问题
方法1:暴力枚举
三层循环,从大到小依次枚举,测试用例数据不是很大,可以通过大多数测试用例。
import java.util.Arrays;
import java.util.Scanner;
/**
* 9.倍数问题
*
*/
public class Main {
static int n, K ;
static int [] a ;
static int sum ;
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
n = input.nextInt() ;
K = input.nextInt() ;
a = new int [n] ;
for(int i=0; i<n; i++){
a[i] = input.nextInt() ;
}
Arrays.sort(a) ;
for(int i=n-1; i>0; i--){ //可以通过60%的测试用例
for(int j=i-1; j>0; j--){
for(int k=j-1; k>0; k--){
sum = a[i] + a[j] + a[k] ;
if(sum % K== 0){
System.out.println(sum);
}
}
}
}
}
}
方法2:排序+搜索
由大到小排序,搜索枚举,找到第一个就结束
import java.util.Arrays;
import java.util.Scanner;
/**
* 从小到大排序,然后搜索枚举
*/
public class Main1 {
static int n, K ;
static int [] a ;
static int [] c ;
static int [] b ;
static boolean flag = false ;
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
n = input.nextInt() ;
K = input.nextInt() ;
a = new int [n+1] ;
c = new int [n+1] ;
b = new int [4] ;
c[0] = Integer.MAX_VALUE ;
for(int i=1; i<=n; i++){
a[i] = input.nextInt() ;
}
Arrays.sort(a) ;
for(int i=1; i<=n; i++){
c[i] = a[n-i+1] ;
}
dfs(c, n, 1) ;
}
private static void dfs(int[] c, int n, int s) {
if(flag){
return ;
}
if(s==4){
int sum = b[1] + b[2] + b[3] ;
if(sum%K==0){
System.out.println(sum);
flag = true ;
}
return ;
}
for(int i=1; i<=n; i++){
if(c[i]<c[s-1]){
b[s] = c[i] ;
dfs(c, n, s+1) ;
}
}
}
}
10.付账问题
思想:贪心策略,拥有的钱由小到大排序,每一次遍历拥有的钱小于均摊值,则全部出,否则,所有人出均摊值,局部最优,全局也最优。
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static double S, ave, avg = 0, s=0;
static int n ;
static double [] a ;
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
n = input.nextInt() ;
S = input.nextDouble() ;
a = new double[n] ;
for(int i=0; i<n; i++){
a[i] = input.nextDouble() ;
}
avg = S / n ;
ave = avg ;
Arrays.sort(a) ;
for(int i=0; i<n; i++){
if(ave > a[i]){
S -= a[i] ;
s += (avg-a[i]) * (avg-a[i]) ;
ave= S / (n-i-1) ;
}else{
double avg1 = S / (n-i) ;
s += (avg-avg1)*(avg-avg1)*(n-i) ;
break ;
}
}
System.out.printf("%.4f", Math.sqrt(s/n));
}
}