头像

寸铁




在线 


最近来访(104)
用户头像
leeqijia
用户头像
acwing_12429
用户头像
常秉
用户头像
nun
用户头像
ji_suan_ji
用户头像
忆丶
用户头像
3J_15
用户头像
Stargazer2277
用户头像
724M78
用户头像
JokerWing
用户头像
acwing_2109
用户头像
Bottom_pump
用户头像
15579642709
用户头像
Zh0uKal1
用户头像
E0柒
用户头像
一万小时定律
用户头像
执梗
用户头像
源泉
用户头像
用户头像
zk_cxz


寸铁
3小时前

Accode

//由于两个都是升序数组
//存在单调性
//我们拿上面最小的元素去和下面最大的元素进行匹配
//因为最小的元素都匹配不了,则该序列中后面的元素必定匹配不了。
//如果说最小的元素匹配后的值比x要大,则移动j指针
//j指针移动至和值小于等于x时停止,移动i后面的数能否匹配。
//匹配过程出现和值>=x时,则继续移动j指针。
import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];
    static int b[]=new int[N];
    public static void main(String []args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int i=0;i<m;i++)b[i]=sc.nextInt();
        for(int i=0,j=m-1;i<n;i++){
           while(j>=0&&a[i]+b[j]>x)j--;
            if(a[i]+b[j]==x){
                System.out.println(i+" "+j);
                return;
            }
    }
}
}



寸铁
3小时前

Accode

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int [N];
    static int b[]=new int [N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int j=0;j<m;j++)b[j]=sc.nextInt();
        for(int i=0;i<n;i++){
            int t=x-a[i];
            //看b序列中是否能二分出答案

            //枚举n次
            //看能否在b序列中找到
            int l=0,r=m-1;
            //确定左右边界
           while(l<=r){
               //这里需要枚举b序列的每一个位置
               //l<=r

               //开始二分
               int mid=l+r>>1;
               //二分的中间点
               if(b[mid]==t){//二分的答案

               System.out.println(i+" "+mid);
               //a序列的位置+" "+b序列的位置
                return;
                //唯一解,找到就返回
               }
               else if(b[mid]>t)r=mid-1;
               //mid这个值比t要大
               //b[mid]已经被比较过,所以r=mid-1;
               else l=mid+1;
               //mid这个值比t要小
               //b[mid]已经被比较过,所以l=mid+1;
           } 
        }
    }
}



寸铁
4小时前

第二期:双指针(基础算法)

蓝桥杯4月8号就要开始了~

还没背熟模板的小伙伴们跟我一起来背模板吧

祝大家4月8号蓝桥杯上岸 ~

不清楚蓝桥杯考什么的点点下方

考点秘籍

想看往期模板的点点下方

往期回顾

模板大全(一)

想看JavaB组填空题的伙伴们点点下方

填空题

双指针和二分的覆盖面广!!!

且较为常用!!!

下面让我们一起来背模板~~~

双指针算法

一般分为两大类:

(1)两个序列中移动i、j指针

在两个序列中分别移动i、j指针
当两个指针均移动到终点时,双指针算法结束
常见的是归并排序的合并过程。

(2)一个序列中移动i、j指针

固定一个指针,然后去移动另一个指针
常见:快速排序。

模板结构:

for(int i=0,j=0;i<n;i++){
    while(j<i&&check(i,j))j++;

    //每道题目的具体逻辑
}

核心思想:将暴力算法优化到O(n)

挖掘某些性质,减少枚举的次数。
直接暴力两重循环:O(n^2)

for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
        //
    }
}

双指针优化:

O(2*n)=O(n)

for(int i=0,j=0;i<=n;i++){
    while(j<i&&check(i,j))j++;
}

双指针算法是一种思想,无固定的模板,这里以模板题为例

模板题

分析

两个指针i,j指针j距离指针i最靠左的距离为多少
右指针往前移动,左指针维持不动或者往前移动,不会往后移动
可以得出i、j的移动具有单调性
因此可以用双指针算法去移动两个指针
while()移动j指针,移动直至j~i这段区间都无重复元素为止。
s[a[i]]=1

注意

while():多次循环
if()判断语句:执行一次

最长连续不重复子序列

//对一段序列用两个指针实现不同位置的同步移动
import java.util.*;
public class Main{
    static int N=100010;;
    static int a[]=new int [N];
    //输入数组
    static int s[]=new int [N];
    //统计序列中每个a[i]出现的次数
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int res=0;
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int i=0,j=0;i<n;i++){
            s[a[i]]++;
            //对于i~j的这段不重复数的区间
            //如果是出现重复数一定是出现在i的位置
            //即s[a[i]]>1

            //注意是While()循环,执行多次判断,移动j指针。
            //写成if的话,是不会一直移动j指针
            while(j<=i&&s[a[i]]>1){
                s[a[j]]--;
                //从j~i这段区间一直除,直至s[a[i]]的个数为1
                j++;
                //每除一次,j往i的方向移动一次
                //除到s[a[i]]=1时,j不再移动
                //此时j~i这段区间的数均不重复
            }
            res=Math.max(res,i-j+1);
            //更新到每个i的最大不连续区间长度
            //可以理解为j最左离i的距离是多少
        }
        System.out.println(res);
    }
}

模板背完后,做做例题吧

例题:AcWing 800. 数组元素的目标和

双指针

//由于两个都是升序数组
//存在单调性
//我们拿上面最小的元素去和下面最大的元素进行匹配
//因为最小的元素都匹配不了,则该序列中后面的元素必定匹配不了。
//如果说最小的元素匹配后的值比x要大,则移动j指针
//j指针移动至和值小于等于x时停止,移动i后面的数能否匹配。
//匹配过程出现和值>=x时,则继续移动j指针。
import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];
    static int b[]=new int[N];
    public static void main(String []args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int i=0;i<m;i++)b[i]=sc.nextInt();
        for(int i=0,j=m-1;i<n;i++){
           while(j>=0&&a[i]+b[j]>x)j--;
            if(a[i]+b[j]==x){
                System.out.println(i+" "+j);
                return;
            }
    }
}
}

二分

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int [N];
    static int b[]=new int [N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int j=0;j<m;j++)b[j]=sc.nextInt();
        for(int i=0;i<n;i++){
            int t=x-a[i];
            //看b序列中是否能二分出答案

            //枚举n次
            //看能否在b序列中找到
            int l=0,r=m-1;
            //确定左右边界
           while(l<=r){
               //这里需要枚举b序列的每一个位置
               //l<=r

               //开始二分
               int mid=l+r>>1;
               //二分的中间点
               if(b[mid]==t){//二分的答案

               System.out.println(i+" "+mid);
               //a序列的位置+" "+b序列的位置
                return;
                //唯一解,找到就返回
               }
               else if(b[mid]>t)r=mid-1;
               //mid这个值比t要大
               //b[mid]已经被比较过,所以r=mid-1;
               else l=mid+1;
               //mid这个值比t要小
               //b[mid]已经被比较过,所以l=mid+1;
           } 
        }
    }
}

AcWing 2816. 判断子序列

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];
    static int b[]=new int[N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int j=0;j<m;j++)b[j]=sc.nextInt();
        //指针的定义不一定需要for循环
        //可以单独定义两个指针然后while循环
        int i=0;
        int j=0;
        while(i<n&&j<m){
            //在两个序列的范围内
            if(a[i]==b[j])i++;
            //找到匹配的情况则i往下走,看i是否可以匹配
            j++;
            //j一直++,往前移动,看是否能够匹配
        }
        //最后一个i=n-1,n-1匹配上j后,则i++后等于n
        //如果刚好i等于n则说明a序列刚好与b序列匹配,输出Yes。
        //这也是一个小技巧
        if(i==n)System.out.println("Yes");
        else System.out.println("No");
    }
}

Java竞赛常用

https://www.myblog.link/2016/11/14/Note-of-java/




寸铁
14小时前

第一期

基础算法(一)

冲刺蓝桥杯省一模板大全来啦~

蓝桥杯4月8号就要开始了~

还没背熟模板的伙伴们背起来!!!

祝大家4月8号蓝桥杯上岸~

不清楚蓝桥杯考什么的点点下方

考点秘籍

想背注释版的伙伴们点点下方

注释版

想看JavaB组填空题的伙伴们点点下方

填空题

快速排序

模板题

题解

不快读快写版

import java.util.*;
public class Main {
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n=sc.nextInt();
    int q[] = new int[n];
    for(int i=0;i<n;i++) {
        q[i]=sc.nextInt();
    }
    quickSort(q,0,n-1);
    for(int i=0;i<n;i++) {
        System.out.print(q[i]+" ");

    }   
}

public static void quickSort(int[] q, int l, int r) {
if(l>=r)return;
int x =q[(l+r)/2],i=l-1,j=r+1;
while(i<j) {
    while(q[++i]<x);
    while(q[--j]>x);
    if(i<j) {
            int t=q[i];
            q[i]=q[j];
            q[j]=t;
    }

}
    quickSort(q,l,j);
    quickSort(q,j+1,r);
}
}

快读快写版

import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws Exception{
        BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[] q = new int[n];
        String[] strs = br.readLine().split(" ");
        for(int i=0;i<q.length;i++)q[i]=Integer.parseInt(strs[i]);
        quickSort(q,0,q.length-1);
        for(int i=0;i<q.length;i++){
            if(i==q.length-1)System.out.print(q[i]);
            else System.out.print(q[i]+" ");
        }

    }

public static void quickSort(int[] q, int l, int r) {
if(l>=r)return;
int x =q[(l+r)/2],i=l-1,j=r+1;
while(i<j) {
    while(q[++i]<x);
    while(q[--j]>x);
    if(i<j) {
            int t=q[i];
            q[i]=q[j];
            q[j]=t;
    }
}

    quickSort(q,l,j);
    quickSort(q,j+1,r);
}
} 

归并排序

模板题

题解

import java.util.*;
public class Main{
    public static void merge_Sort(int q[],int l,int r){
        if(l>=r)return;
        int mid=(l+r)>>1;
        merge_Sort(q,l,mid);
        merge_Sort(q,mid+1,r);
         int k=0,i=l,j=mid+1;
         int temp[]=new int[r-l+1];
        while(i<=mid&&j<=r){
            if(q[i]<=q[j]&&j<=r)temp[k++]=q[i++];
            else temp[k++]=q[j++];
        }
        while(i<=mid)temp[k++]=q[i++];
        while(j<=r)temp[k++]=q[j++];
        for(int a=0,b=l;b<=r;a++,b++){
            q[b]=temp[a];
        }
    }
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int q[]=new int[n];
        for(int i=0;i<n;i++)q[i]=sc.nextInt();
        merge_Sort(q,0,n-1);
        for(int i=0;i<n;i++){
            System.out.print(q[i]+" ");
        }
    }
}

二分

模板题

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];

    public static void main(String []args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int q=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        while(q-->0){
            int x=sc.nextInt();
            int l=0,r=n-1;
            while(l<r){
                int mid=l+r>>1;
                if(a[mid]>=x)r=mid;
                else l=mid+1;
            }
            if(a[l]!=x)System.out.println("-1 -1");
            else{
                System.out.print(l+" ");
               l=0;
               r=n-1;
               while (l<r){
                  int mid=l+r+1>>1;
                  if(a[mid]<=x)l=mid;
                  else r=mid-1;
            }
            System.out.println(l);
        }
    }
    } 
}



寸铁
14小时前

第一期: 二分(基础算法)

蓝桥杯4月8号就要开始了

还没背熟模板的小伙伴们跟我一起来背模板吧

祝大家4月8号蓝桥杯上岸 ~

不清楚蓝桥杯考什么的点点下方

考点秘籍

想直接看纯模板的见下方

纯模板

想看JavaB组填空题的伙伴们点点下方

填空题

众所周知,二分是蓝桥杯考查热点!

万物皆可二分!!!

下面让我们一起来背二分模板吧!

步骤总结

(1)确定左右边界

l=0,r=n-1

(2)二分

写法1:

while(l<r){
int mid=l+r+1>>1;
if(a[mid]<=x)l=mid;
else r=mid-1;
}

写法2:


while(l<r){
if(a[mid]>=x)r=mid;
else l=mid+1;
}

(3)二分的答案:L

根据题目要求进行变化

模板题:数的范围:
经典真题:
杨辉三角形
统计子矩阵

二分(开背)

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];
    public static void main(String []args){
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();
        int q=scan.nextInt();
        for(int i=0;i<n;i++){
            a[i]=scan.nextInt();
        }
       while(q-->0){
           int x=scan.nextInt();
           int l=0,r=n-1;
           //左边界 l=0
           //右边界 r=n-1

           //满足l<r这一条件则开始二分
           //二分到最后l==r,输出答案即可。
           while(l<r){
               int mid=l+r>>1;
               if(a[mid]>=x)r=mid;
               //当前元素比目标值大,则继续缩小(左移)右边界

               else l=mid+1;
               //否则则增大(右移)左边界
           }
           if(a[l]!=x)System.out.println("-1 -1");
           //找不到则输出-1 -1
           else{
               System.out.print(l+" ");
               l=0;r=n-1;
               while(l<r){
                   int mid=l+r+1>>1;
                   //对于l=mid的情况
                   //mid等于l+r+1
                   // +1一定不要漏掉!!!
                   if(a[mid]<=x)l=mid;
        //二分出的元素大小小于目标值x,说明需要移动左边界。
        //往右方向移动去寻找答案。
                   else r=mid-1;
        //否则则需要移动右边界           
               }
               System.out.println(l);
               //输出二分出的位置l
           }
       }
    }

}

模板背完后,做做例题吧

没时间解释了,快上车!

例题:AcWing 800. 数组元素的目标和

二分

import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int [N];
    static int b[]=new int [N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int j=0;j<m;j++)b[j]=sc.nextInt();
        for(int i=0;i<n;i++){
            int t=x-a[i];
            //看b序列中是否能二分出答案

            //枚举n次
            //看能否在b序列中找到
            int l=0,r=m-1;
            //确定左右边界
           while(l<=r){
               //这里需要枚举b序列的每一个位置
               //l<=r

               //开始二分
               int mid=l+r>>1;
               //二分的中间点
               if(b[mid]==t){//二分的答案

               System.out.println(i+" "+mid);
               //a序列的位置+" "+b序列的位置
                return;
                //唯一解,找到就返回
               }
               else if(b[mid]>t)r=mid-1;
               //mid这个值比t要大
               //b[mid]已经被比较过,所以r=mid-1;
               else l=mid+1;
               //mid这个值比t要小
               //b[mid]已经被比较过,所以l=mid+1;
           } 
        }
    }
}

双指针

//由于两个都是升序数组
//存在单调性
//我们拿上面最小的元素去和下面最大的元素进行匹配
//因为最小的元素都匹配不了,则该序列中后面的元素必定匹配不了。
//如果说最小的元素匹配后的值比x要大,则移动j指针
//j指针移动至和值小于等于x时停止,移动i后面的数能否匹配。
//匹配过程出现和值>=x时,则继续移动j指针。
import java.util.*;
public class Main{
    static int N=100010;
    static int a[]=new int[N];
    static int b[]=new int[N];
    public static void main(String []args)
    {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        int x=sc.nextInt();
        for(int i=0;i<n;i++)a[i]=sc.nextInt();
        for(int i=0;i<m;i++)b[i]=sc.nextInt();
        for(int i=0,j=m-1;i<n;i++){
           while(j>=0&&a[i]+b[j]>x)j--;
            if(a[i]+b[j]==x){
                System.out.println(i+" "+j);
                return;
            }
    }
}
}



寸铁
16小时前

欢迎大家评论交流关注收藏~~~

总结

几套做下来,发现蓝桥杯出题有一些规律:

每年必考对数位的操作+日期问题!!!

签到题:重点考察字符串的操作

模拟+推公式

前几道题基本上是基础算法:

像前缀和、双指针、二分、差分、各类排序

万物皆可二分~

这些都是基础算法!!!

后面的出一两道DP题!

压轴基本上是DFS、BFS!

当然,考虑到时间复杂度的问题,还涉及各种优化模型!

涉及数论像质数筛,快速幂、质因数分解、平衡树、双指针、前缀和对某个问题进行优化等等。

对于基础薄弱的同学,后期着重复习基础题+板子题!!!

刷真题网站:

注:不同的Oj评测多少有些不同,大家理性看待,重在做法!
https://www.dotcpp.com/
https://www.acwing.com/(蓝辅)
https://www.lanqiao.cn/
https://www.luogu.com.cn/



活动打卡代码 AcWing 4653. 数位排序

寸铁
16小时前

如果你觉得这篇题解对你有用,可以点个赞或关注再走呗~

分析

直接取出数位相加
对于数组的每个数按数位之和小的在前,数位之和大的在后。
对于数位相等的情况
按小的数在前,大的数在后。

总结

几套做下来,发现蓝桥杯出题有一些规律:

每年必考对数位的操作+日期问题!!!

签到题:重点考察字符串的操作

模拟+推公式

前几道题基本上是基础算法:

像前缀和、双指针、二分、差分、各类排序

万物皆可二分~

这些都是基础算法!!!

后面的出一两道DP题!

压轴基本上是DFS、BFS!

当然,考虑到时间复杂度的问题,还涉及各种优化模型!

涉及数论像质数筛,快速幂、质因数分解、平衡树、双指针、前缀和对某个问题进行优化等等。

对于基础薄弱的同学,后期着重复习基础题+板子题!!!

Accode

import java.util.*;
public class Main{
    public static void main(String []args) {
    Scanner sc  =new Scanner(System.in);
    int n=sc.nextInt();
    int m=sc.nextInt();
    Integer arr[]=new Integer[n];
    Integer s[]=new Integer[n+1];
    //Array.sort排序是从数组下标0开始排序
    //需要定义数组为Integer类型,s数组存的是i+1的数位之和,需要多开一个空间。
    //所以a[]的读入从下标0开始
    for(int i=0;i<n;i++) {
        arr[i]=i+1;
        s[i+1]=sum(i+1);
    }
    //对于相等的数位之和的两数,按小的在前,大的在后
    //即return a-b;

    //其他的则直接按照数位之和的大小排a、b两数即可
    Arrays.sort(arr,(a,b)->{
        if(s[a]==s[b])return a-b;
        return s[a]-s[b];
    });


    System.out.println(arr[m-1]);
    //数组下标从0开始,输出为m-1。


    }
    public static int sum(int x) {
        //求数字的各个数位之和
        int res=0;
        while(x!=0) {
            res+=x%10;
            //将每个数位相加
            x/=10;
            //依次去掉取出的每一位
        }
        return res;
    }
}




寸铁
16小时前

如果你觉得这篇题解对你有用,可以点个赞或关注再走呗~

详情请见

Accode

import java.util.*;
public class Main{
    static int N=200010;
    static int a[]=new int[N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        long sum=0;
        long cnt=0;
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
            sum+=a[i];
            cnt+=a[i]*a[i];
        }
        System.out.println((sum*sum-cnt)/2);
    }

}


活动打卡代码 AcWing 4644. 求和

寸铁
16小时前

如果你觉得这篇题解对你有用,可以点个赞或关注再走呗~

详情请见

Accode

import java.util.*;
public class Main{
    static int N=200010;
    static int a[]=new int[N];
    public static void main(String []args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        long sum=0;
        long cnt=0;
        for(int i=0;i<n;i++){
            a[i]=sc.nextInt();
            sum+=a[i];
            cnt+=a[i]*a[i];
        }
        System.out.println((sum*sum-cnt)/2);
    }

}



寸铁
17小时前

如果你觉得这篇题解对你有用,可以点点关注再走呗~

考点:模拟+分割字符

注意

java本题需要用到分割字符
先读入一个串a
再用a.substring(1)
分割出第二个字符即循环次数。

读入方式2:

String s=sc.next();
int n=s.charAt(1)-'0';
注意:需要转码,获得字符串中的字符后减去‘0’才能变成数字
没有转码则直接输出0!!!

读入方式3

char a[]=sc.next().toCharArray();
int n=a[1]-'0';
与第二种类似,不过是先转为字符数组再转码

Accode

import java.util.*;
public class Main{
    public static void main(String[]args) {
        Scanner in = new Scanner(System.in);
        String a = in.nextLine();
        int n = Integer.parseInt(a.substring(1));//获取字符串的第二个数
        int l=1189;//长边
        int w=841;//短边
        for(int i=1;i<=n;i++) {//根据读取的数,确定循环次数
            int t=l;//临时变量储存每一次循环长边
            l=w;//上一个的宽边等于更新的长边
            w=t/2;//对长边除2来更新短边      
        }
        System.out.println(l);
        System.out.println(w);
    }
}

Accode

import java.util.*;
public class Main{
    public static void main(String []args){
        Scanner in =new Scanner(System.in);
         String a = in.nextLine();
        int n =Integer.parseInt(a.substring(1));
        int l=1189;
        int w= 841;
        while(n-->0){
            int t=l;
            l=w;
            w=t/2;
            if(l<w){
                int temp=l;
                l=w;
                w=temp;
            }
        }
        System.out.println(l);
        System.out.println(w);
    }
}