Acwing算法基础课

算法基础课)

    • *算法基础课*
      • 基础算法
        • 二分
          • Acwing 789 数的范围
          • Acwing 790 数的三次方根
          • Acwing 1460 我在哪?
          • Acwing 1221 四平方和
          • Acwing 113 特殊排序
        • 高精度
          • Acwing 791 高精度加法
          • Acwing 792 高精度减法
          • Acwing 793 高精度乘法
          • Acwing 794 高精度除法
        • 前缀和与差分
          • Acwing 795 前缀和
          • Acwing 796 子矩阵的和
          • Acwing 797 差分
          • Acwing 798 差分矩阵
          • Acwing 3956 截断数组
          • Acwing 1230 K倍区间
          • Acwing 99 激光炸弹
          • Acwing 3729 改变数组元素
          • Acwing 100 增减序列
        • 双指针算法
          • Acwing 799 最长连续不重复子序列
          • Acwing 800 数组元素的目标和
          • Acwing 3768 字符串删减
        • 位运算
          • Acwing 801
        • 离散化
          • Acwing 802
        • 区间合并
          • Acwing 803
      • 数据结构
        • 单调栈
          • Acwing 830
        • 单调队列
          • Acwing 154
        • KMP
          • Acwing 831
        • Trie
          • Acwing 835
        • 并查集
          • Acwing 836
          • AcWing 837
          • Acwing 240
      • 搜索与图论
        • DFS
          • Acwing 842 排列数字
          • Acwing 843 n-皇后问题
          • Acwing 3777 砖块
        • BFS
          • Acwing 844
          • Acwing 845
        • 树与图的深度优先遍历
          • Acwing 846
        • 树与图的宽度优先遍历
          • Acwing 847
        • 拓扑排序
          • Acwing 848
        • Dijkstra
          • Acwing 849
      • 数学知识
        • 质数
          • Acwing 866
          • Acwing 867
          • Acwing 868
        • 约数
          • Acwing 869
          • Acwing 870
          • Acwing 871
          • Acwing 872
        • 欧拉函数
          • Acwing 873
          • Acwing 874
        • 快速幂
          • Acwing 875
          • Acwing 876
        • 扩展欧几里得算法
          • Acwing 877
          • Acwing 878
        • 中国剩余定理
          • Acwing 204
        • 高斯定理
          • Acwing 883
          • Acwing 884
        • 求组合数
          • Acwing 885
          • Acwing 886
          • Acwing 887
          • Acwing 888
          • Acwing 898
        • 容斥原理
          • Acwing 890
        • 博弈论
          • Acwing 891
          • Acwing 892
          • Acwing 893
          • Acwing 894
      • 动态规划
        • 背包问题
          • Acwing 2 01背包问题
          • Acwing 3 完全背包问题
          • Acwing 4 多重背包问题
          • Acwing 5 分组背包问题
        • 线性DP
          • Acwing 889 数字三角形
          • Acwing 895 最长上升子序列
          • Acwing 896 最长上升子序列Ⅱ
          • Acwing 897 最长公共子序列
          • Acwing 899 编辑距离
        • 区间DP
          • Acwing 282 石子合并
        • 计数类DP
          • Acwing 900 整数划分
        • 数位统计DP
          • Acwing 338 计数问题
        • 状态压缩DP
          • Acwing 蒙德里安的梦想
          • Acwing 91 最短Hamilton路径
        • 树形DP
          • Acwing 285 没有上司的舞会

算法基础课

基础算法

二分

Acwing 789 数的范围

给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。如果数组中不存在该元素,则返回“-1 -1”。输入格式第一行包含整数n和q,表示数组长度和询问个数。第二行包含n个整数(均在1~10000范围内),表示完整数组。接下来q行,每行包含一个整数k,表示一个询问元素。输出格式共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。如果数组中不存在该元素,则返回“-1 -1”。

数据范围

1≤n≤100000

1≤q≤10000

1≤k≤10000


输入格式
6 3
1 2 2 3 3 4
3
4
5
输出格式
3 4
5 5
-1 -1

代码


import java.util.Scanner;

// 给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。对于每个查询,
//返回一个元素k的起始位置和终止位置(位置从0开始计数)。如果数组中不存在该元素,则返回“-1 -1”。
//输入格式第一行包含整数n和q,表示数组长度和询问个数。第二行包含n个整数(均在1~10000范围内),表示完整数组。
//接下来q行,每行包含一个整数k,表示一个询问元素。输出格式共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。如果数组中不存在该元素,则返回“-1 -1”。
class 数的范围{
    static int maxn=100010;
    static int []a=new int[maxn];
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int t=input.nextInt();
        for(int i=0;i<n;i++){
            a[i]=input.nextInt();
        }
        for(int i=0;i<t;i++){
            int x=input.nextInt();
            int temp=find(0,n-1,x);
            if(a[temp]!=x){System.out.println("-1 -1");continue;}//直接特判
            System.out.println(temp);//左边界
            System.out.println(a[find(temp+1,n-1,x)]==x?find(temp+1,n-1,x):temp);//右边界,因为是从左边界+1开搜,可能出现右边界等于左边界,故特判

        }
        input.close();
    }
    public static int find(int l,int r,int x){
        while(l<r){
            int mid=(l+r)>>1;
            if(x<=a[mid])r=mid;
            else l=mid+1;
        }
        return l;
    }
}
Acwing 790 数的三次方根

给定一个浮点数n,求它的三次方根。输入格式共一行,包含一个浮点数n。输出格式共一行,包含一个浮点数,表示问题的解。注意,结果保留6位小数。

数据范围

−10000≤n≤10000

−10000≤n≤10000

输入样例
1000.00
输出样例
10.000000

代码

import java.util.Scanner;

public class 数的三次方根 {
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        double x=input.nextDouble();
        double l=-10000;
        double r=100000;
        double res=bsearch(x,l,r);
  
        System.out.printf("%.6f",res);
        input.close();
    }
    public static double bsearch(double x,double l,double r){
        double eps=1e-8;
        while((r-l)>eps){
            double mid=(l+r)/2;
            if(mid*mid*mid>=x)r=mid;
            else l=mid;

        }
        return l;
    }
}

Acwing 1460 我在哪?

农夫约翰出门沿着马路散步,但是他现在发现自己可能迷路了!沿路有一排共 N 个农场。不幸的是农场并没有编号,这使得约翰难以分辨他在这条路上所处的位置。然而,每个农场都沿路设有一个彩色的邮箱,所以约翰希望能够通过查看最近的几个邮箱的颜色来唯一确定他所在的位置。每个邮箱的颜色用 A…Z 之间的一个字母来指定,所以沿着道路的 N 个邮箱的序列可以用一个长为 N的由字母 A…Z 组成的字符串来表示。某些邮箱可能会有相同的颜色。约翰想要知道最小的 K 的值,使得他查看任意连续 K个邮箱序列,他都可以唯一确定这一序列在道路上的位置。例如,假设沿路的邮箱序列为 ABCDABC 。约翰不能令 K=3,因为如果他看到了 ABC,则沿路有两个这一连续颜色序列可能所在的位置。最小可行的 K 的值为 4,因为如果他查看任意连续 4个邮箱,那么可得到的连续颜色序列可以唯一确定他在道路上的位置。

输入格式

输入的第一行包含 N,第二行包含一个由 N个字符组成的字符串,每个字符均在 A…Z 之内。

输出格式

输出一行,包含一个整数,为可以解决农夫约翰的问题的最小 K值。

数据范围

1N100

输入样例:

7
ABCDABC

输出样例:

4

代码

public class 我在哪里 {
    static int maxn=100010;
    static long p[]=new long[maxn];
    static long h[]=new long[maxn];
    static int P=131;
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        char str[]=input.next().toCharArray();
        p[0]=1L;
        for(int i=0;i<n;i++){
            h[i+1]=h[i]*P+str[i];
            p[i+1]=p[i]*P;
        }
        find(1,n,str.length);
        input.close();
    }
    static void find(int l,int r,int n){
        while(l<r){
            int mid=(l+r)>>1;
            if(check(mid,n))r=mid;
            else l=mid+1;
        }
        System.out.println(l);;
    }
    static boolean check(int mid,int n){
        for(int i=mid;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(hash(i-mid+1,i)==hash(j-mid+1,j))return false;
            }
        }
        return true;
    }
    static long hash(int l,int r){
        return h[r]-h[l-1]*p[r-l+1];
    }
}

Acwing 1221 四平方和

四平方和定理,又称为拉格朗日定理:

每个正整数都可以表示为至多 4个正整数的平方和。

如果把 0包括进去,就正好可以表示为 4个数的平方和。

比如:

5= 0 2 0^2 02+ 0 2 0^2 02+ 1 2 1^2 12+ 2 2 2^2 22

对于一个给定的正整数,可能存在多种平方和的表示法。

要求你对 4个数排序:

0abcd

并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。

输入格式

输入一个正整数 N

输出格式

输出4个非负整数,按从小到大排序,中间用空格分开。

数据范围

0<N< 5 ∗ 1 0 6 5*10^6 5106

输入样例:

5

输出样例:

0 0 1 2

代码

import java.util.HashMap;
import java.util.Scanner;
public class 四平方和 {
    static HashMap<Integer,Integer>hash=new HashMap<>();
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        //先枚举后两位
        for(int c=0;c*c<=n;c++){
            for(int d=0;d*d<=n;d++){
                if(!hash.containsKey(c*c+d*d))hash.put(c*c+d*d,d);
            }
        }
        //枚举前两位
        for(int a=0;a*a<=n;a++){
            for(int b=0;b*b<=n;b++){
                int t=n-a*a-b*b;
                if(hash.containsKey(t)){
                    int d=hash.get(t);
                    int c=(int)Math.sqrt(t-d*d);
                    System.out.printf("%d %d %d %d%n",a,b,c,d);
                    return;
                }
            }
        }
        input.close();
    }
}

Acwing 113 特殊排序

N个元素,编号 1,2…N,每一对元素之间的大小关系是确定的,关系具有反对称性,但不具有传递性。

注意 :不存在两个元素大小相等的情况。也就是说,元素的大小关系是 NN 个点与 N ( N − 1 ) 2 \frac{N(N-1)}{2} 2N(N1) 条有向边构成的任意有向图。然而,这是一道交互式试题,这些关系不能一次性得知,你必须通过不超过 10000次提问来获取信息,每次提问只能了解某两个元素之间的关系。现在请你把这 N个元素排成一行,使得每个元素都小于右边与它相邻的元素。你可以通过我们预设的 bool 函数 compare 来获得两个元素之间的大小关系。例如,编号为 ab 的两个元素,如果元素 a小于元素 b,则 compare(a,b) 返回 true,否则返回 false。将 N个元素排好序后,把他们的编号以数组的形式输出,如果答案不唯一,则输出任意一个均可。

数据范围

1N1000

输入样例

[[0, 1, 0], [0, 0, 0], [1, 1, 0]]

输出样例

[3, 1, 2]

代码

// The compare API is defined in the parent class Relation:
//      boolean compare(int a, int b);
//      return boolean means whether a is less than b.

class Solution extends Relation {
    public int[] specialSort(int N) {
        int []res=new int[N];
        res[0]=1;//第一条边
        int len=1;
        for(int i=2;i<=N;i++){
            int l=0;int r=len-1;
            while(l<r){
                int mid=(l+r+1)>>1;
                if(compare(res[mid],i))l=mid;///一直往右搜索
                else r=mid-1;
            }
            res[len++]=i;
            for(int j=len-2;j>r;j--)swap(res,j,j+1);
            if(compare(i,res[r]))swap(res,r,r+1);
        }
        return res;
    }
    static public void swap(int a[],int x,int y){
        int temp=a[x];
        a[x]=a[y];
        a[y]=temp;
    }
}

高精度

Acwing 791 高精度加法
Acwing 792 高精度减法
Acwing 793 高精度乘法
Acwing 794 高精度除法

前缀和与差分

Acwing 795 前缀和

输入一个长度为n的整数序列。
接下来再输入m个询问,每个询问输入一对l,r。
对于每个询问,输出原序列中从第l个数到第 r 个数的和。

输入格式
第一行包含两个整数n和m。
第二行包含n个整数,表示整数数列。
接下来m行,每行包含两个整l和r,表示一个询问的区间范围。

输出格式
共m行,每行输出一个询问的结果。

数据范围
1 ≤ l ≤ r ≤ n ,
1 ≤ n , m ≤ 100000 ,
− 1000 ≤ 数列中元素的值 ≤ 1000

输入样例

5 3
2 1 3 6 4
1 2
1 3
2 4

输出样例

3
6
10

代码

import java.util.ArrayList;
import java.util.Scanner;

public class 前缀和 {
    public static void main(String[]args) {
        final int maxn=100005;
        int []a=new int[maxn];
        int []s=new int[maxn];
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int m=input.nextInt();
        for(int i=1;i<=n;i++){
            a[i]=input.nextInt();
        }
        for(int i=1;i<=n;i++){
            s[i]=s[i-1]+a[i];
        }
        ArrayList<Pair>query=new ArrayList<Pair>();
        for(int i=0;i<m;i++){
            int l=input.nextInt();
            int r=input.nextInt();
        query.add(new Pair(l, r));
        }
  
        for(Pair item:query){
            int l=item.x-1;
            int r=item.y;
            System.out.println(s[r]-s[l]);
        }
        input.close();

    }
   
}
//  class Pair{
//     int x;
//     int y;
//     public Pair(int x,int y){
//         this.x=x;
//         this.y=y;
//     }
// }


Acwing 796 子矩阵的和

输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式
第一行包含三个整数 n ,m ,q。

接下来 n 行,每行包含 m 个整数,表示整数矩阵。

接下来 q 行,每行包含四个整数 x1,y1,x2,y2,表示一组询问。

输出格式
共 q 行,每行输出一个询问的结果。

数据范围
1 ≤ n , m ≤ 1000 , 1≤n,m≤1000,
1 ≤ q ≤ 200000 ,1 ≤ x 1 ≤ x 2 ≤ n ,1≤y1≤y2≤m,− 1000 ≤ 矩阵内元素的值 ≤ 1000

输入样例:

3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例:

17
27
21

代码


import java.util.Scanner;

public class 子矩阵的和 {
  
    public static void main(String []args){
     int maxn=1005;
  
     int [][]a=new int[maxn][maxn];
    int [][]s=new int[maxn][maxn];
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int m=input.nextInt();
        int q=input.nextInt();
  
  
        //二维前缀和
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[i][j]=input.nextInt();
                s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j];
            }
        }
        //子矩阵
            for(int i=1;i<=q;i++){
                int x1=input.nextInt();
                int y1=input.nextInt();
                int x2=input.nextInt();
                int y2=input.nextInt();
                System.out.println(s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
            }
  
        input.close();
    }
  
}

Acwing 797 差分

输入一个长度为n的整数序列。

接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。

请你输出进行完所有操作后的序列。

输入格式
第一行包含两个整数n和m。

第二行包含n个整数,表示整数序列。

接下来m行,每行包含三个整数l,r,c,表示一个操作。

输出格式
共一行,包含n个整数,表示最终序列。

数据范围
1≤n,m≤100000,
1≤l≤r≤n,
−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000
输入样例:

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

输出样例:

3 4 5 3 4 2

代码

import java.util.*;
public class 差分 {
    static int maxn=100010;
    static int []a=new int[maxn];
    static int []b=new int[maxn];
    public static void insert(int l,int r,int c){
        b[l]+=c;
        b[r+1]-=c;
    }
    public static void main(String[]args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int m=input.nextInt();
        for(int i=1;i<=n;i++){
            a[i]=input.nextInt();
            // b[i]=a[i]-a[i-1];
            insert(i,i,a[i]);
        }
        for(int i=1;i<=m;i++){
            int l=input.nextInt();
            int r=input.nextInt();
            int c=input.nextInt();
            insert(l, r, c);
        }
        for(int i=1;i<=n;i++){
            a[i]=a[i-1]+b[i];
            System.out.println(a[i]);
        }
  
        input.close();
    }
}

Acwing 798 差分矩阵

输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1,y1) 和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。

每个操作都要将选中的子矩阵中的每个元素的值加上 c。

请你将进行完所有操作后的矩阵输出。

输入格式
第一行包含整数 n,m,q。

接下来 n 行,每行包含 m 个整数,表示整数矩阵。

接下来 q 行,每行包含 5 个整数 x1,y1,x2,y2,c,表示一个操作。

输出格式
共 n 行,每行 m 个整数,表示所有操作进行完毕后的最终矩阵。

数据范围
1≤n,m≤1000,
1≤q≤100000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤c≤1000,
−1000≤矩阵内元素的值≤1000

输入样例:

3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1

输出样例:

2 3 4 1
4 3 4 1
2 2 2 2

代码

import java.util.*;
public class 差分矩阵 {
    static int maxn=10010;
    static int [][]a=new int[maxn][maxn];
    static int [][]b=new int[maxn][maxn];
    static void insert(int x1,int y1,int x2,int y2,int c){
        b[x1][y1]+=c;
        b[x1][y2+1]-=c;
        b[x2+1][y1]-=c;
        b[x2+1][y2+1]+=c;

    }
   public static void main(String[]args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int m=input.nextInt();
        int q=input.nextInt();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[i][j]=input.nextInt();
                insert(i,j,i,j,a[i][j]);
            }
        }
        for(int i=1;i<=q;i++){
            int x1=input.nextInt();
            int y1=input.nextInt();
            int x2=input.nextInt();
            int y2=input.nextInt();
            int c=input.nextInt();
            insert(x1,y1,x2,y2,c);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+b[i][j]; 
                System.out.println(a[i][j]);
            }
        }
        input.close();
    }
}

Acwing 3956 截断数组

给定一个长度为 nn 的数组a1,a2,…,an。现在,要将该数组从中间截断,得到三个非空子数组。要求,三个子数组内各元素之和都相等。请问,共有多少种不同的截断方法?

输入格式

第一行包含整数 n

第二行包含 n个整数 a1,a2,…,an。

输出格式

输出一个整数,表示截断方法数量。

数据范围

前六个测试点满足 1n10
所有测试点满足 1n105,10000ai10000

输入样例1:

4
1 2 3 3

输出样例1:

1

输入样例2:

5
1 2 3 4 5

输出样例2:

0

输入样例3:

2
0 0

输出样例3:

0

代码

import java.util.Scanner;
public class Main {
    static int maxn=100010;
    static int a[]=new int[maxn];
    static int s[]=new int[maxn];
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int cnt=0;
        for(int i=1;i<=n;i++){
            a[i]=input.nextInt();
            s[i]=s[i-1]+a[i];
        }
        int t=s[n]/3;
        long ans=0;
        if(s[n]%3==0){
            for(int i=1;i<n-1;i++){
                if(s[i]==t)cnt++;//第一刀的切法
                if(s[n]-s[i+1]==t)ans+=(long)cnt;//第二刀切法,不能取第i+1个项,否则不能同时满足两个条件
            }
        }
        System.out.println(ans);
        input.close();
    }
}

Acwing 1230 K倍区间

给定一个长度为 NN 的数列,A1,A2,…AN,如果其中一段连续的子序列Ai,Ai+1,…Aj 之和是 K的倍数,我们就称这个区间 [i,j]是 K倍区间。

你能求出数列中总共有多少个 K倍区间吗?

输入格式

第一行包含两个整数 N和 K。

以下 N行每行包含一个整数 Ai。

输出格式

输出一个整数,代表 K 倍区间的数目。

数据范围

1N,K100000,1≤Ai≤100000

输入样例:

5 2
1
2
3
4
5

输出样例:

6

代码

import java.util.Scanner;
public class Main{
    static int maxn=100010;
    static long a[]=new long[maxn];
    static long s[]=new long[maxn];
    static int cnt[]=new int[maxn];
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        long K=input.nextLong();
        for(int i=1;i<=n;i++){
            a[i]=input.nextLong();
            s[i]=s[i-1]+a[i];
        }
        long sum=0;cnt[0]=1;//cnt[0]初始化为1,因为1-i项不用和其他人配对
        for(int i=1;i<=n;i++){
            sum+=cnt[(int)(s[i]%K)]++;//s[R] % k == s[L] % k
            // for(int j=i+1;j<=n;j++){
            //     if((s[j]-s[i])%K==0)sum++;
            // }
        }
        System.out.println(sum);
        input.close();
    }
}

Acwing 99 激光炸弹

地图上有 N个目标,用整数 Xi,Yi 表示目标在地图上的位置,每个目标都有一个价值 Wi。

注意 :不同目标可能在同一位置。

现在有一种新型的激光炸弹,可以摧毁一个包含 R×R 个位置的正方形内的所有目标。

激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个正方形的边必须和 x,y 轴平行。

求一颗炸弹最多能炸掉地图上总价值为多少的目标。

输入格式

第一行输入正整数 NR,分别代表地图上的目标数目和正方形包含的横纵位置数量,数据用空格隔开。

接下来 NN 行,每行输入一组数据,每组数据包括三个整数 Xi,Yi,Wi,分别代表目标的 x坐标,y 坐标和价值,数据用空格隔开。

输出格式

输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。

数据范围

0R10
0 0≤Xi,Yi≤5000
≤Wi≤1000

输入样例:

2 1
0 0 1
1 1 1

输出样例:

1

代码

import java.util.Scanner;
public class Main{
    static int maxn=5010;
    static int a[][]=new int[maxn][maxn];
    static int s[][]=new int[maxn][maxn];
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int r=input.nextInt();
        r=Math.min(5001,r);//r最大值为5001
        int ans=0;
        for(int i=1;i<=n;i++){
            int x=input.nextInt()+1;
            int y=input.nextInt()+1;
            int w=input.nextInt();
            a[x][y]+=w;//目标可能在同一位置
  
        }
        //枚举每个坐标,坐标最大值为5001
        for(int i=1;i<=5001;i++){
            for(int j=1;j<=5001;j++){
                s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];//二维前缀和数组
            }
        }
        for(int i=r;i<=5001;i++){
        for(int j=r;j<=5001;j++){
        ans=Math.max(ans,s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]);}}//求子矩阵
        System.out.println(ans);
        input.close();
    }
}

Acwing 3729 改变数组元素

给定一个空数组 V和一个整数数组 a1,a2,…,an。

现在要对数组 V进行 n次操作。

i 次操作的具体流程如下:

  1. 从数组 V尾部插入整数 0
  2. 将位于数组 V 末尾的 ai 个元素都变为 1(已经是 1 的不予理会)。

注意:

  • ai 可能为 0,即不做任何改变。
  • ai 可能大于目前数组 V 所包含的元素个数,此时视为将数组内所有元素变为 1

请你输出所有操作完成后的数组 V

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 nn。

第二行包含 n个整数 a1,a2,…,an。

输出格式

每组数据输出一行结果,表示所有操作完成后的数组 V,数组内元素之间用空格隔开。

数据范围

1≤T≤20000,
1≤n≤2×105,
0≤ai≤n,
保证一个测试点内所有 n的和不超过 2×105。

输入样例:

3
6
0 3 0 0 1 3
10
0 0 0 1 0 5 0 0 0 2
3
0 0 0

输出样例:

1 1 0 1 1 1
0 1 1 1 1 1 0 0 1 1
0 0 0

代码

import java.util.Arrays;
import java.util.Scanner;
public class Main {
    static int maxn=200010;
    static int b[]=new int[maxn];
    public static void insert(int l,int r){//差分
        b[l]+=1;
        b[r+1]-=1;
    }
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int t=input.nextInt();
        for(int i=1;i<=t;i++){//t次查询
            Arrays.fill(b,0);//初始化
            int n=input.nextInt();
            for(int j=1;j<=n;j++){
                int x=input.nextInt();
                if(x==0)continue;
                else if(x>j)insert(1,j);
                else{
                    insert(j-x+1,j);
                }
            }
            for(int k=1;k<=n;k++)b[k]+=b[k-1];//前缀和
            for(int j=1;j<=n;j++){
                if(b[j]==0)System.out.printf("%d ",0);
                else System.out.printf("%d ",1);
            }
            System.out.println();
        }
        input.close();
    }
}

Acwing 100 增减序列

给定一个长度为 n的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。

求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。

输入格式

第一行输入正整数 n

接下来 n行,每行输入一个整数,第 i+1 行的整数代表 ai。

输出格式

第一行输出最少操作次数。

第二行输出最终能得到多少种结果。

数据范围

0<n105,
0≤ai<2147483648

输入样例:

4
1
1
2
2

输出样例:

1
2

代码

import java.util.Scanner;
public class Main {
    static int maxn=100010;
    static int a[]=new int[maxn];
    static int b[]=new int[maxn];
    static void insert(int l,int r,int x){
        b[l]+=x;
        b[r+1]-=x;
    }
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        for(int i=1;i<=n;i++)a[i]=input.nextInt();
        for(int i=1;i<=n;i++)insert(i,i,a[i]);
        long p=0;long q=0;
        for(int i=2;i<=n;i++){
            if(b[i]>0)p+=b[i];
            else q-=b[i];
        }
        System.out.println(Math.max(p,Math.abs(q)));
        System.out.println(Math.abs(p-q)+1);
        input.close();
    }
}

双指针算法

Acwing 799 最长连续不重复子序列

题目描述
给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。

输入格式
第一行包含整数 n 。

第二行包含 n 个整数(均在 0∼10^50 范围内),表示整数序列。

输出格式
共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。

数据范围
1≤n≤10^5

输入样例:

5
1 2 2 3 5

输出样例:

3

代码

import java.util.Scanner;

public class 最长连续不重复子序列 {
    final static int maxn=1005;
    public static void main(String []args){
  
        int res=0;
        Scanner cin=new Scanner(System.in);
        int n=cin.nextInt();
        int []temp=new int[maxn];
        int []a=new int[maxn];
        for(int i=0;i<n;i++){
            a[i]=cin.nextInt();
        }
        int j=0;
        for(int i=0;i<n;i++){
   
            temp[a[i]]++;
            //i为终点,所以每次出现重复只能是再终点
            while(temp[a[i]]>1){
                temp[a[j]]--;//将原来起点的次数-1
                j++;//起点右移,直到区间无重复
            }
            res=Math.max(res,i-j+1);
  
        }
        System.out.println(res);
        cin.close();
    }
}
//哈希表实现
// import java.util.Scanner;
// import java.util.ArrayList;
// import java.util.HashMap;
// public class 最长连续不重复子序列{
//     public static void main(String []args){
//         Scanner input=new Scanner(System.in);
//         int n=input.nextInt();
//         ArrayLista=new ArrayList<>();
//         HashMapmp=new HashMap<>();
//         for(int i=0;i
//             int x=input.nextInt();
//             a.add(x);
//         }
//         int j=0;
//         int res=0;
//         for(int i=0;i
//             mp.put(a.get(i),mp.getOrDefault(a.get(i), 0)+1);//默认为零
//             while(j1){
//                 mp.put(a.get(j),mp.get(a.get(j))-1);
//                 j++;
//             }
//             res=Math.max(res,i-j+1);
//         }
//         System.out.println(res);
//         input.close();
//     }
// }
Acwing 800 数组元素的目标和

给定两个升序排序的有序数组 A 和 B,以及一个目标值 x。

数组下标从 0 开始。

请你求出满足 A[i]+B[j]=x 的数对 (i,j)。

数据保证有唯一解。

输入格式
第一行包含三个整数 n,m,x,分别表示 A 的长度,B 的长度以及目标值 x。

第二行包含 n 个整数,表示数组 A。

第三行包含 m 个整数,表示数组 B。

输出格式
共一行,包含两个整数 i 和 j。

数据范围
数组长度不超过 105。
同一数组内元素各不相同。
1≤数组元素≤109
输入样例:

4 5 6
1 2 4 7
3 4 6 8 9

输出样例:

1 1

代码

import java.util.*;
public class 数组元素的目标和 {
    static final int maxn=1000010;
    static int []a=new int[maxn];
    static int []b=new int[maxn];
  
    public static void main(String[]args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int m=input.nextInt();
        int x=input.nextInt();
        for(int i=0;i<n;i++){
            a[i]=input.nextInt();
        }
        for(int j=0;j<m;j++){
            b[j]=input.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);
                System.out.println(j);
                break;
            }
        }
        input.close();
    }
}

Acwing 3768 字符串删减

给定一个由 n个小写字母构成的字符串。

现在,需要删掉其中的一些字母,使得字符串中不存在连续三个或三个以上的 x

请问,最少需要删掉多少个字母?

如果字符串本来就不存在连续的三个或三个以上 x,则无需删掉任何字母。

输入格式

第一行包含整数 n

第二行包含一个长度为 n 的由小写字母构成的字符串。

输出格式

输出最少需要删掉的字母个数。

数据范围

3n100

输入样例1:

6
xxxiii

输出样例1:

1

输入样例2:

5
xxoxx

输出样例2:

0

输入样例3:

10
xxxxxxxxxx

输出样例3:

8

代码

import java.util.Scanner;
public class Main {
    public static void main(String []args){
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        char []a=input.next().toCharArray();
        int sum=0,cnt=0;
        for(int i=0;i<n;i++){
            if(a[i]=='x'){
                cnt++;
                if(cnt==3){
                    sum++;
                    cnt--;
                }
            }else{
                cnt=0;
            }
        }
        System.out.println(sum);
        input.close();
    }
}

位运算

Acwing 801

离散化

Acwing 802

区间合并

Acwing 803

数据结构

单调栈

Acwing 830

单调队列

Acwing 154

KMP

Acwing 831

Trie

Acwing 835

并查集

Acwing 836
AcWing 837
Acwing 240

搜索与图论

DFS

Acwing 842 排列数字

给定一个整数n,将数字1~n排成一排,将会有很多种排列方法。

现在,请你按照字典序将所有的排列方法输出。

输入格式
共一行,包含一个整数n。

输出格式
按字典序输出所有排列方案,每个方案占一行。

数据范围
1≤n≤7

输入样例:

3

输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

代码

import java.util.*;
public class 排列数字 {
    static int n;
    static int maxn=10010;
    static int []path=new int[maxn];
    static boolean []flag=new boolean[maxn];
    public static void main(String[]args){
        Scanner input=new Scanner(System.in);
        n=input.nextInt();
        dfs(0);
        input.close();
    }
    public static void dfs(int u){
        if(u==n){
            for(int j=0;j<n;j++)
            System.out.print(path[j]);
            System.out.println();
        }
        for(int i=1;i<=n;i++){
            if(!flag[i]){
            path[u]=i;
            flag[i]=true;
            dfs(u+1);
            flag[i]=false;
            path[u]=0;
        }}
    }
}

Acwing 843 n-皇后问题

n− 皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
现在给定整数 n,请你输出所有的满足条件的棋子摆法。

输入格式
共一行,包含整数 n。

输出格式
每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。
其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
注意:行末不能有多余空格。
输出方案的顺序任意,只要不重复且没有遗漏即可。

数据范围
1≤n≤9
输入样例:

4

输出样例:

.Q..
...Q
Q...
..Q.

..Q.
Q...
...Q
.Q..

代码

import java.util.*;
public class n黄后问题 {
    static int maxn=10010;
    static int n;
    static char[][]a=new char[maxn][maxn];
    static boolean[]row=new boolean[maxn];
    static boolean[]col=new boolean[maxn];
    static boolean[]dig=new boolean[maxn];
    static boolean[]udg=new boolean[maxn];
    public static void main(String[]args){
        Scanner input=new Scanner(System.in);
        n=input.nextInt();
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                a[i][j]='.';
            }
        }
        dfs(0,0,0);//s代表皇后放置个数
        input.close();
    }
    public static void dfs(int x,int y,int s){
        if(y==n){
            y=0;
            x++;
        }
        if(x==n){
            if(s==n)
            {
            for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
            System.out.print(a[i][j]);
        }
            System.out.println();
        }
    }
    return;
        }
  
        dfs(x, y+1, s);//不放皇后
        //放皇后
        if(!row[x]&&!col[y]&&!dig[x+y]&&!udg[x-y+n]){
            a[x][y]='Q';
            row[x]=col[y]=dig[x+y]=udg[x-y+n]=true;
            dfs(x, y+1, s+1);
            row[x]=col[y]=dig[x+y]=udg[x-y+n]=false;
            a[x][y]='.';
        }
    }
}

Acwing 3777 砖块

n 个砖块排成一排,从左到右编号依次为 1n

每个砖块要么是黑色的,要么是白色的。

现在你可以进行以下操作若干次(可以是 0次):

选择两个相邻的砖块,反转它们的颜色。(黑变白,白变黑)

你的目标是通过不超过 3n3n 次操作,将所有砖块的颜色变得一致。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含一个整数 n

第二行包含一个长度为 n 的字符串 s。其中的每个字符都是 WB,如果第 i个字符是 W,则表示第 i 号砖块是白色的,如果第 i 个字符是 B,则表示第 i 个砖块是黑色的。

输出格式

每组数据,如果无解则输出一行 −1。

否则,首先输出一行 k,表示需要的操作次数。

如果 k>0,则还需再输出一行 k个整数,**p1,p2,…,pk。其中 pi 表示第 i 次操作,选中的砖块为 pi 和 pi+1 号砖块。

如果方案不唯一,则输出任意合理方案即可。

数据范围

1T10
2≤n≤200。

输入样例:

4
8
BWWWWWWB
4
BWBB
5
WWWWW
3
BWB

输出样例:

3
6 2 4
-1
0
2
2 1

代码


BFS

Acwing 844
Acwing 845

树与图的深度优先遍历

Acwing 846

树与图的宽度优先遍历

Acwing 847

拓扑排序

Acwing 848

Dijkstra

Acwing 849

数学知识

质数

Acwing 866
Acwing 867
Acwing 868

约数

Acwing 869
Acwing 870
Acwing 871
Acwing 872

欧拉函数

Acwing 873
Acwing 874

快速幂

Acwing 875
Acwing 876

扩展欧几里得算法

Acwing 877
Acwing 878

中国剩余定理

Acwing 204

高斯定理

Acwing 883
Acwing 884

求组合数

Acwing 885
Acwing 886
Acwing 887
Acwing 888
Acwing 898

容斥原理

Acwing 890

博弈论

Acwing 891
Acwing 892
Acwing 893
Acwing 894

动态规划

背包问题

Acwing 2 01背包问题
Acwing 3 完全背包问题
Acwing 4 多重背包问题
Acwing 5 分组背包问题

线性DP

Acwing 889 数字三角形
Acwing 895 最长上升子序列
Acwing 896 最长上升子序列Ⅱ
Acwing 897 最长公共子序列
Acwing 899 编辑距离

区间DP

Acwing 282 石子合并

计数类DP

Acwing 900 整数划分

数位统计DP

Acwing 338 计数问题

状态压缩DP

Acwing 蒙德里安的梦想
Acwing 91 最短Hamilton路径

树形DP

Acwing 285 没有上司的舞会

你可能感兴趣的:(算法,数据结构,深度优先)