当前位置:   article > 正文

蓝桥杯洛谷第一周刷题总结

蓝桥杯洛谷第一周刷题总结

前言

注:1.P8649 K倍区间答案参考于“晏秋”,P8742 砝码称重答案参考于“一只风里”,感谢两位大佬提供的解法!

2.如有不正确的地方,欢迎指正,谢谢!

前缀和

P8772 求和

  1. import java.util.Scanner;
  2. public class Mian {
  3. public static void main(String[] args) {
  4. // TODO Auto-generated method stub
  5. Scanner scan = new Scanner(System.in);
  6. int n = scan.nextInt();//输入整数的个数
  7. int[] A = new int[n];//用一个数组接收这些整数
  8. int pre = 0;
  9. long[] sum = new long[n];
  10. //输入整数
  11. for(int i = 0;i < n;i++) {
  12. int num = scan.nextInt();
  13. A[i] = num;
  14. pre += num;
  15. sum[i] += pre;//求出每个整数对应的前缀和
  16. }
  17. //用前缀和数组进行优化
  18. //a1*a2 + a1*a3 + ... + a1*an
  19. //a1*(a2 + a3 + ... +an) = a1*(sum(n) - sum(1))
  20. long total = 0;//用于接收最终的结果——所求的和
  21. for(int i = 0;i < n;i++) {
  22. total += A[i] * (sum[n - 1] - sum[i]);
  23. }
  24. System.out.println(total);
  25. }
  26. }

P8649 K倍区间

答案参考:晏秋

  1. import java.util.Scanner;
  2. public class main {
  3. public static void main(String[] args) {
  4. // TODO Auto-generated method stub
  5. Scanner scan = new Scanner(System.in);
  6. int N = scan.nextInt();
  7. int K = scan.nextInt();
  8. int[] A = new int[N];
  9. long sum = 0;
  10. long[] B = new long[K];//存放各个余数的个数(这里不太理解为什么要用long)
  11. for(int i = 0;i < N;i++) {
  12. A[i] = scan.nextInt();
  13. sum += A[i];//把前缀和求出来
  14. B[(int)(sum % K)]++;
  15. }
  16. long count = 0;//接收结果
  17. count = B[0];//余数为0的个数(余数为0则必定为K的倍数)
  18. for(int i = 0;i < K;i++) {
  19. //两个同余的数相减一定为K倍区间
  20. //用排列组合公式Cn,即从具有相同余数的前缀和里取出两个前缀和进行相减
  21. count += (B[i] * (B[i] - 1)) / 2;
  22. }
  23. System.out.println(count);
  24. }
  25. }

并查集

基本操作

并查集主要用于不相交集合的合并问题

1.初始化,即将每个节点的祖先节点指向自己

2.查询祖先节点find

3.合并两个节点:将一个节点的祖先节点指向另一个节点的祖先节点

P8654 合根植物

  1. import java.util.Scanner;
  2. public class Main {
  3. static int[] fa;
  4. public static void main(String[] args) {
  5. // TODO Auto-generated method stub
  6. Scanner scan = new Scanner(System.in);
  7. int m = scan.nextInt();
  8. int n = scan.nextInt();
  9. int k = scan.nextInt();
  10. //用二维数组存放连根数据
  11. int[][] arr = new int[k][2];
  12. for(int i = 0;i < k;i++) {
  13. int a = scan.nextInt();
  14. int b = scan.nextInt();
  15. arr[i][0] = a;
  16. arr[i][1] = b;
  17. }
  18. //初始化:将每个植物节点的祖先节点指向自己
  19. //为了方便,数组0位置不使用
  20. fa = new int[m * n + 1];
  21. for(int i = 1;i < fa.length;i++) {
  22. fa[i] = i;
  23. }
  24. int count = m*n;
  25. for(int i = 0;i < k;i++) {
  26. int x_fa = find(arr[i][0]);
  27. int y_fa = find(arr[i][1]);
  28. //当x与y的祖先节点相同时,无需将x的祖先节点指向y的祖先节点,count无需减1
  29. if(x_fa == y_fa) {
  30. continue;
  31. }
  32. else {
  33. //让x的祖先节点指向y的祖先节点
  34. fa[x_fa] = y_fa;
  35. count--;
  36. }
  37. }
  38. System.out.println(count);
  39. }
  40. public static int find(int node) {
  41. if(fa[node] == node) {
  42. return node;
  43. }
  44. else {
  45. //比如1→5→6,1的父节点为5,则find(5),即继续寻找5的父节点
  46. //直到找到最终节点6,6的父节点指向自己,则进入if语句,return 6;所以fa[1] = 6;
  47. fa[node] = find(fa[node]);//该步进行了路径压缩
  48. return fa[node];
  49. }
  50. }
  51. }

二分查找

P8647 分巧克力

  1. import java.util.Scanner;
  2. public class Main {
  3. static int N;
  4. static int K;
  5. static int[] H;
  6. static int[] W;
  7. public static void main(String[] args) {
  8. // TODO Auto-generated method stub
  9. Scanner scan = new Scanner(System.in);
  10. N = scan.nextInt();
  11. K = scan.nextInt();
  12. H = new int[N];//存放各块巧克力的长
  13. W = new int[N];//存放各块巧克力的宽
  14. for(int i = 0;i < N;i++) {
  15. int h = scan.nextInt();
  16. int w = scan.nextInt();
  17. H[i] = h;
  18. W[i] = w;
  19. }
  20. System.out.println(find(1,100000));
  21. }
  22. //二分查找
  23. public static int find(int l,int r) {
  24. int ans = -1;
  25. int mid = 0;
  26. while(l <= r) {
  27. mid = (l + r) / 2;
  28. if(account(mid)) {
  29. //当以mid为边长分出巧克力块数大于孩子数时
  30. //继续向右边寻找更大的边长
  31. ans = mid;
  32. l = mid + 1;
  33. }
  34. else {
  35. //当以mid为边长分出巧克力块数小于孩子数时
  36. //向左寻找(将边长缩小一点,快数会多一点)
  37. r = mid - 1;
  38. }
  39. }
  40. return ans;
  41. }
  42. public static boolean account(int a) {
  43. int count = 0;
  44. for(int i = 0;i < N;i++) {
  45. count += (H[i] / a)*(W[i] / a);
  46. }
  47. if(count >= K) {
  48. return true;
  49. }
  50. else {
  51. return false;
  52. }
  53. }
  54. }

01背包问题

P8742 砝码称重

答案参考:一只风里

  1. import java.util.Scanner;
  2. import java.lang.reflect.Array;
  3. import java.util.ArrayList;
  4. import java.util.HashSet;
  5. public class Main {
  6. public static void main(String[] args) {
  7. // TODO Auto-generated method stub
  8. Scanner scan = new Scanner(System.in);
  9. int N = scan.nextInt();
  10. int[] fama = new int[N];//用于存放各个砝码的重量
  11. for(int i = 0;i < N;i++) {
  12. fama[i] = scan.nextInt();
  13. }
  14. HashSet<Long> set = new HashSet<Long>();
  15. set.add(0L);
  16. for(int i = 0;i < N;i++) {
  17. //不能直接使用set的迭代器遍历,迭代器不能及时发现set的更新
  18. //(自己的理解,如不对请指正,谢谢!)
  19. ArrayList<Long> list = new ArrayList<Long>(set);
  20. for(long k:list) {
  21. set.add(fama[i] + k);
  22. set.add(Math.abs(k - fama[i]));
  23. }
  24. }
  25. set.remove(0L);
  26. System.out.println(set.size());
  27. }
  28. }

深度优先搜索(DFS)

P8605 网络寻路

  1. import java.util.Scanner;
  2. public class Main {
  3. static int sum;//统计路径
  4. static int[] node;//用于标记节点是否已访问
  5. static int[][] map;//用于标记两个节点之间是否有线路
  6. public static void main(String[] args) {
  7. // TODO Auto-generated method stub
  8. Scanner scan = new Scanner(System.in);
  9. int N = scan.nextInt();
  10. int M = scan.nextInt();
  11. //为了方便,数组0位置不使用,从1开始
  12. node = new int[N + 1];
  13. map = new int[N + 1][N + 1];
  14. for(int i = 0;i < M;i++) {
  15. int u = scan.nextInt();
  16. int v = scan.nextInt();
  17. map[u][v] = 1;//1表示节点之间有线路
  18. map[v][u] = 1;
  19. }
  20. for(int i = 1;i < N + 1;i++) {
  21. node[i] = 0;//node数组初始化,0表示未访问,1表示已访问
  22. }
  23. for(int i = 1;i < N + 1;i++) {
  24. dfs(i,i,0);
  25. }
  26. System.out.println(sum);
  27. }
  28. //传入三个参数,start表示起始节点,temp表示当前节点,step表示步长(即连接节点的线路条数)
  29. //1.判断是否为终点,非终点时继续递归调用dfs
  30. //2.递归调用dfs前需要将当前节点设为已访问,为了防止走回头路;
  31. // 调用结束后需要将当前节点设为未访问,为了探索其它路径时可以访问该节点
  32. //此题注意:当步长为2时,需要判断当前节点与起始节点是否有线路,如果有,则sum++
  33. public static void dfs(int start,int temp,int step) {
  34. if(step == 3) {
  35. sum++;
  36. return;
  37. }
  38. else if(step == 2) {
  39. if(map[temp][start] == 1) {
  40. sum++;
  41. }
  42. for(int k = 1;k < map[temp].length;k++) {
  43. if(map[temp][k] == 1 && node[k] == 0) {
  44. node[temp] = 1;
  45. dfs(start,k,step + 1);
  46. node[temp] = 0;
  47. }
  48. }
  49. }
  50. else {
  51. for(int k = 1;k < map[temp].length;k++) {
  52. //如果temp和k之间有线路,且k未访问
  53. if(map[temp][k] == 1 && node[k] == 0) {
  54. node[temp] = 1;
  55. //当前节点变为k,步长+1
  56. dfs(start,k,step + 1);
  57. node[temp] = 0;
  58. }
  59. }
  60. }
  61. }
  62. }

有两个测试点未通过,显示超出空间限制,请问大家有什么更好的解吗?

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/385367
推荐阅读
相关标签
  

闽ICP备14008679号