当前位置:   article > 正文

第十二届蓝桥杯大赛软件类省赛Java研究生组-题解_蓝桥杯研究生组java分果果

蓝桥杯研究生组java分果果

目录

试题A:卡片

试题B:相乘

试题C:直线

试题D:路径

试题E:回路计数

试题F:时间显示

试题G:最少砝码

试题H:杨辉三角

试题I:双向排序

试题J:分果果


试题A:卡片

答案:3181

思路:num数组记录0-9的个数,从1开始判断,如果数字的各位中含有字母c,则num[c]减1,直至最后num[c]<0,则不能凑出。

  1. public class Main {
  2. public static void main(String[] args) {
  3. int [] num = {2021,2021,2021,2021,2021,2021,2021,2021,2021,2021} ;
  4. for(int i=1; ; i++){
  5. String s = String.valueOf(i) ;
  6. for(int j=0; j<s.length(); j++){
  7. int c = s.charAt(j) - '0' ;
  8. num[c] -- ;
  9. if(num[c]<0){
  10. System.out.println(i-1);
  11. return ;
  12. }
  13. }
  14. }
  15. }
  16. }

试题B:相乘

答案:17812964

思路:枚举+判断即可。

  1. public class Main {
  2. public static void main(String[] args) {
  3. for(long i=1; i<=1000000007; i++){
  4. if((i * 2021)%1000000007==999999999){
  5. System.out.println(i);
  6. return ;
  7. }
  8. }
  9. System.out.println(0);
  10. }
  11. }

试题C:直线

答案:40257

思路:这题并不太容易想到,其实就是枚举所有点,判断对应的斜率和截距组成的不同坐标的个数,可以用set自动去重。

公式:y-y1=(y2-y1)/(x2-x1)*(x-x1)

故:k=(y2-y1) / (x2-x1) ; b=(x2*y1-x1*y2)/(x2-x1)

  1. import java.util.Set;
  2. import java.util.TreeSet;
  3. public class Main {
  4. public static void main(String[] args) {
  5. Set<String> set = new TreeSet<>() ;
  6. double k, b ;
  7. for(int x1=0; x1<20; x1++){
  8. for(int y1=0; y1<=20; y1++){
  9. for(int x2=x1+1; x2<20; x2++){
  10. for(int y2=0; y2<=20; y2++){
  11. k = 1.0 * (y2 - y1) / (x2 - x1) ;
  12. b = 1.0 * (x2 * y1 - x1 * y2) / (x2 - x1) ;
  13. set.add(k+","+b) ;
  14. }
  15. }
  16. }
  17. }
  18. System.out.println(set.size()+20); //要加上斜率不存在的20个
  19. }
  20. }

试题D:路径

答案:10266837

思路:单源最短路径,Dijkstra算法,建立邻接表,如果节点之差绝对值小于等于21,建立边,对应的边权值为两节点值得最小公倍数,dist数组记录到达相应节点得最短路径,通过优先队列按照权值最小排序,每次选择更小得路径 ,更新当前路径。

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.PriorityQueue;
  4. public class Main{
  5. public static void main(String[] args) {
  6. List<int []> g[] = new List [2022] ;
  7. for(int i=0; i<2022; i++){
  8. g[i] = new ArrayList<>() ;
  9. }
  10. for(int i=1; i<=2020; i++){
  11. for(int j=i+1; j<=2021; j++){
  12. if(Math.abs(i-j)<=21){
  13. g[i].add(new int [] {j, f(i,j)}) ;
  14. g[j].add(new int [] {i, f(i,j)}) ;
  15. }
  16. }
  17. }
  18. int [] dist = new int [2022] ;
  19. for(int i=1; i<2022; i++){
  20. dist[i] = Integer.MAX_VALUE ;
  21. }
  22. dist[1] = 0 ;
  23. //优先队列,按权值进行升序排序
  24. PriorityQueue<int []> queue = new PriorityQueue<int[]>((a,b)->a[1]!=b[1] ? a[1] - b[1] : a[0] - b[0]) ;
  25. queue.add(new int[]{1,0}) ; //到达的节点和对应的权值
  26. while(!queue.isEmpty()){
  27. int [] p = queue.poll() ;
  28. int x = p[0], w = p[1] ;
  29. if(dist[x]<w){
  30. continue;
  31. }
  32. for(int [] edges : g[x]){
  33. int y = edges[0], d = dist[x] + edges[1] ;
  34. if(d<dist[y]){
  35. dist[y] = d ;
  36. queue.add(new int [] {y, d}) ;
  37. }
  38. }
  39. }
  40. System.out.println(dist[2021]);
  41. }
  42. private static int f(int a, int b){
  43. return a * b / gcd(a,b) ;
  44. }
  45. private static int gcd(int a, int b){
  46. if(b==0){
  47. return a ;
  48. }else{
  49. return gcd(b,a%b) ;
  50. }
  51. }
  52. }

试题E:回路计数

答案:881012367360

思路:状压+dp,f[i][j]表示从1出发走到j且经过i得方案数,用二进制表示经过点的状态。

  1. public class Main {
  2. static boolean [][] edges ;
  3. static int m = 1 << 21 ;
  4. static long [][] f ;
  5. public static void main(String[] args) {
  6. edges = new boolean [21][21] ;
  7. f = new long [m][21] ;
  8. for(int i=1; i<=21; i++){
  9. for(int j=1; j<=21; j++){
  10. if(gcd(i,j)==1){
  11. edges[i-1][j-1] = true ;
  12. }
  13. }
  14. }
  15. f[1][0] = 1 ;
  16. for(int i=0; i<=m-1; i++){
  17. for(int j=0; j<=20; j++){
  18. if((i>>j & 1) != 0){
  19. for(int k=0; k<=20; k++){
  20. if((i-(1<<j)>>k & 1)!=0 && edges[k][j]){
  21. f[i][j] += f[i-(1<<j)][k] ;
  22. }
  23. }
  24. }
  25. }
  26. }
  27. long ans = 0 ;
  28. for(int i=1; i<=20; i++){
  29. ans += f[m-1][i] ;
  30. }
  31. System.out.println(ans);
  32. }
  33. private static int gcd(int m, int n) {
  34. if(n==0){
  35. return m ;
  36. }else{
  37. return gcd(n, m%n) ;
  38. }
  39. }
  40. }

试题F:时间显示

思路:模拟,将总毫秒数对一天的毫秒数取余,得到的time是剩余需要操作的毫秒数,计算出时分秒即可,如果是个位数,需要在前面补零。

  1. import java.util.Scanner;
  2. public class Main {
  3. public static void main(String[] args) {
  4. Scanner input = new Scanner(System.in) ;
  5. long t = input.nextLong() ;
  6. long ms = 24 * 60 * 60 * 1000 ;
  7. long time = t % ms ;
  8. long hour = time / 3600000 ;
  9. long min = (time % 3600000) / 60000 ;
  10. long sec = ((time%3600000) % 60000) / 1000 ;
  11. String h = String.valueOf(hour) ;
  12. String m = String.valueOf(min) ;
  13. String s = String.valueOf(sec) ;
  14. if(h.length()==1){
  15. h = "0" + h ;
  16. }
  17. if(m.length()==1){
  18. m = "0" + m ;
  19. }
  20. if(s.length()==1){
  21. s = "0" + s ;
  22. }
  23. System.out.println(h + ":" + m + ":" + s);
  24. }
  25. }

试题G:最少砝码

思路:规律题,我们想使用最少的砝码称出任意小于等于N的正整数数量,我们用count记录 砝码个数,weight记录所需的最后一个砝码的重量,total记录砝码能称出的总重量,这样会发现weight每次应该乘以3,而total等于上一轮的toal加上这次的weight。

  1. import java.util.Scanner;
  2. public class Main {
  3. public static void main(String[] args) {
  4. Scanner input = new Scanner(System.in) ;
  5. int N = input.nextInt() ;
  6. int count = 1 ; //砝码个数
  7. int weight = 1 ; //最后一个砝码的重量
  8. int total = 1 ; //砝码能称出的总重量
  9. while(total<N){
  10. count ++ ;
  11. weight *= 3 ;
  12. total += weight ;
  13. }
  14. System.out.println(count);
  15. }
  16. }

试题H:杨辉三角

思路:这题想AC,不太容易,很容易爆内存,那就先混分吧,开辟二维数组记录杨辉三角,然后转成一维数组,vis数组标记是否是第一次出现,index数组记录第一次出现的位置。

  1. import java.util.Scanner;
  2. public class Main {
  3. public static void main(String[] args) {
  4. Scanner input = new Scanner(System.in) ;
  5. int N = input.nextInt() ;
  6. int [][] a = new int [20][20] ;
  7. int [] ans = new int [100000000] ;
  8. int [] vis = new int [100000000] ;
  9. int [] index = new int [100000000] ;
  10. for(int i=0; i<20; i++){
  11. for(int j=0; j<=i; j++){
  12. if(i==j || j==0){
  13. a[i][j] = 1 ;
  14. }else{
  15. a[i][j] = a[i-1][j-1] + a[i-1][j] ;
  16. }
  17. }
  18. }
  19. int k = 0 ;
  20. for(int i=0; i<20; i++) {
  21. for (int j = 0; j <= i; j++) {
  22. ans[k++] = a[i][j] ;
  23. if(vis[a[i][j]]==0){
  24. vis[a[i][j]] = 1 ;
  25. index[a[i][j]] = k ;
  26. }
  27. }
  28. }
  29. System.out.println(index[N]);
  30. }
  31. }

试题I:双向排序

思路:这题考的是线段树,对于混分大师来说,根据题意模拟双向排序就行。

  1. import java.util.Arrays;
  2. import java.util.Scanner;
  3. public class Main {
  4. static int [] a ;
  5. public static void main(String[] args) {
  6. Scanner input = new Scanner(System.in) ;
  7. int n = input.nextInt() ;
  8. int m = input.nextInt() ;
  9. a = new int [n] ;
  10. for(int i=1; i<=n; i++){
  11. a[i-1] = i ;
  12. }
  13. for(int i=1; i<=m; i++){
  14. int p = input.nextInt() ;
  15. int q = input.nextInt() ;
  16. if(p==0) {
  17. desc(a,0,q-1);
  18. }else if(p==1){
  19. asc(a,q-1,n-1) ;
  20. }
  21. }
  22. for(int i=0; i<a.length; i++){
  23. System.out.print(a[i]+" ");
  24. }
  25. }
  26. private static void desc(int[] a, int begin, int end) {
  27. int [] ans = new int [end-begin+1] ;
  28. int j = 0 ;
  29. for(int i=begin; i<=end; i++){
  30. ans[j++] = a[i] ;
  31. }
  32. Arrays.sort(ans);
  33. j-- ;
  34. for(int i=begin; i<=end; i++){
  35. a[i] = ans[j--] ;
  36. }
  37. }
  38. private static void asc(int[] a, int begin, int end) {
  39. int [] ans = new int [end-begin+1] ;
  40. int j = 0 ;
  41. for(int i=begin; i<=end; i++){
  42. ans[j++] = a[i] ;
  43. }
  44. Arrays.sort(ans);
  45. j = 0 ;
  46. for(int i=begin; i<=end; i++){
  47. a[i] = ans[j++] ;
  48. }
  49. }
  50. }

试题J:分果果

思路:有些难的动态规划了,思路可以参考这个:蓝桥杯 - 分果果 - SOSCHINA - 博客园

  1. import java.io.*;
  2. import java.util.*;
  3. public class Main {
  4. public static void main(String[] args) { new Main().run(); }
  5. int INF = 0x3F3F3F3F;
  6. void run() {
  7. InputReader in = new InputReader(System.in);
  8. int n = in.readInt(), m = in.readInt(), ans = INF;
  9. int[][][] dp = new int[m + 1][n + 1][n + 1];
  10. int[] S = new int[n + 1];
  11. for (int i = 1; i <= n; i++)
  12. S[i] = S[i - 1] + in.readInt();
  13. for (int i = 0; i <= m; i++)
  14. for (int j = 0; j <= n; j++)
  15. for (int k = 0; k <= j; k++) dp[i][j][k] = INF;
  16. dp[0][0][0] = 0;
  17. for (int min = S[n] * 2 / m; min > 0; min--) {
  18. for (int i = 1; i <= m; i++)
  19. for (int j = 1; j <= n; j++) {
  20. int trans2 = 0, trans3 = 0;
  21. for (int k = 1; k <= j; k++) {
  22. dp[i][j][k] = dp[i][j][k - 1];
  23. while (trans2 < k && S[j] - S[trans2 + 1] >= min &&
  24. max(dp[i - 1][trans2 + 1][trans2 + 1], S[j] - S[trans2 + 1]) <= max(dp[i - 1][trans2][trans2], S[j] - S[trans2])) trans2++;
  25. if (S[j] - S[trans2] >= min)
  26. dp[i][j][k] = min(dp[i][j][k], max(dp[i - 1][trans2][trans2], S[j] - S[trans2]));
  27. while (trans3 < k && S[j] - S[trans3 + 1] >= min &&
  28. max(dp[i - 1][k][trans3 + 1], S[j] - S[trans3 + 1]) <= max(dp[i - 1][k][trans3 + 1], S[j] - S[trans3])) trans3++;
  29. if (S[j] - S[trans3] >= min)
  30. dp[i][j][k] = min(dp[i][j][k], max(dp[i - 1][k][trans3], S[j] - S[trans3]));
  31. }
  32. }
  33. ans = min(ans, dp[m][n][n] - min);
  34. }
  35. System.out.println(ans);
  36. }
  37. int max(int arg1, int arg2) { return arg1 > arg2 ? arg1 : arg2; }
  38. int min(int arg1, int arg2) { return arg1 < arg2 ? arg1 : arg2; }
  39. class InputReader {
  40. BufferedReader reader;
  41. StringTokenizer token;
  42. InputReader(InputStream in) {
  43. this.reader = new BufferedReader(new InputStreamReader(in));
  44. }
  45. String read() {
  46. while (token == null || !token.hasMoreTokens()) {
  47. try {
  48. token = new StringTokenizer(reader.readLine());
  49. } catch (IOException e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. return token.nextToken();
  54. }
  55. int readInt() { return Integer.parseInt(read()); }
  56. }
  57. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/342377?site
推荐阅读
相关标签
  

闽ICP备14008679号