AcWing蓝桥杯总结Day1

75 阅读3分钟

由数据范围反推时间复杂度

对C++而言,评测机1秒之内大概可以运行10810^8次 一般ACM或者笔试题的时间限制是1秒或2秒。 在这种情况下,C++代码中的操作次数控制在10710810^7∼10^8 为最佳

下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择

  1. n<=30n <= 30 指数级别, dfs+剪枝,状态压缩dp
  2. n<=102=>O(n2)n <= 10^2 => O(n^2) floyd,dp,高斯消元
  3. n<=103=>O(n2),O(n2logn)n <= 10^3 => O(n^2), O(n^2logn) dp, 二分, 朴素版Dijkstra, 朴素版Prim, Bellman-Ford
  4. n<=104=>O(nn)n <= 10^4 => O(n*\sqrt{n}) 块状链表,分块,莫队
  5. n<=105=>O(nlogn)n <= 10^5 => O(nlogn) 各种sort, 线段树, 树状数组, set/map, heap, 拓扑排序,Dijkstra+heap, Prim+heap, Kruskal, SPFA, 求凸包,求半平面交,二分,CDQ分治,整体二分,后缀数组,树链剖分,动态树
  6. n<=106=>O(n)以及常数较小的O(nlogn)算法n <= 10^6 => O(n) 以及常数较小的O(nlogn)算法 单调队列,hash,双指针扫描,BFS,并查集,KMP,AC自动机, 常数比较小的O(nlogn)算法O(nlogn)算法 sort, 树状数组,heap,dijkstra,SPFA
  7. n<=107=>O(n)n <= 10^7 => O(n) 双指针扫描,KMP,AC自动机,线性筛素数
  8. n<=109=>O(n)n <= 10^9 => O(\sqrt{n}) 判断质数
  9. n<=1018=>O(logn)n <= 10^{18} => O(logn) 最大公约数,快速幂,数位DP
  10. n<=101000=>O(log2n)n <= 10^{1000} => O(log^2n) 高精度加减乘除
  11. n<=10100000=>O(logk×loglogk)n <= 10^{100000} => O(logk \times loglogk) k表示位数,高精度加减,FFT/NTT

所有递归=>递归搜索树

例题

AcWing92. 递归实现指数型枚举

个人题解

import java.util.*;

public class Main{

     static Deque<Integer> path = new LinkedList<>();


     static void dfs(int n, int index){
  
        for(int i : path){
            System.out.print(i+" ");
         }
        System.out.println();
    
         
         for(int i = index; i <= n; ++i){
             path.addLast(i);
             dfs(n, i+1);
             path.removeLast();
         }
     }

     public static void main(String[] args){
         Scanner sc = new Scanner(System.in);
         int n = sc.nextInt();
         dfs(n,1);
     }
}




标准题解

import java.util.*;

public class Main {

    static int n;

    /**
     * 状态, 记录每个位置当前的状态:
     * 0: 还没考虑
     * 1: 选
     * 2: 不选
     */
    static int[] st;

    static void dfs(int u){ 

        if(u > n){
           for(int i = 1; i <= n; ++i){
               if(st[i] == 1) System.out.print(i + " ");
           }
           System.out.println();
           return;
        }

        st[u] = 2;
        dfs(u+1);   //第一个分支: 不选u
        st[u] = 0;  //恢复现场

        st[u] = 1;
        dfs(u+1);   //第二个分支: 选u
        st[u] = 0;

    }


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        st = new int[n + 1];
        
        dfs(1);
    }
}

状态压缩

import java.util.Scanner;

public class Main {

    static int n;

    /**
     * 状态, 记录每个位置当前的状态:
     * 0: 不选
     * 1: 选
     */
    static int[] st;


    static void dfs(int u){
        if(u > n){
           for(int i = 1; i <= n; ++i){
               if(st[i] == 1) System.out.print(i + " ");
           }
           System.out.println();
           return;
        }
        
        dfs(u+1);   //第一个分支 不选

        st[u] = 1;
        dfs(u+1);   //第二个分支 选
        st[u] = 0;

    }


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        st = new int[n + 1];

        dfs(1);
    }
}

AcWing94. 递归实现排列型枚举

个人题解:

import java.util.Scanner;

public class Main {

    static int n;

    /**
     *  used[i]: i是否已经被使用
     */
    static boolean[] used;

    static int[] way;

    static void dfs(int index){
        if(index > n){
            for (int i = 1; i <= n; i++) {
                System.out.print(way[i] + " ");
            }
            System.out.println();
            return;
        }

        
        for(int i = 1; i <= n; i++){
            if(used[i]) continue;
            used[i] = true;
            way[index] = i;
            dfs(index + 1);
            used[i] = false;
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        used = new boolean[n + 1];
        way = new int[n + 1];
        
        dfs(1);
    }
}

习题

AcWing93. 递归实现组合型枚举

import java.util.*;

public class Main {
    static int n;

    static int m;
    
    static int[] state;


    /**
     * 
     * @param index state的当前下标
     * @param start 起始位置 [start,n]
     */
    static void dfs(int index, int start){
        if(index > m){
            for (int j = 1; j <= m; ++j) {
                System.out.print(state[j] + " ");
            }
            System.out.println();
            return;
        }
        
        for(int i = start; i <= n - m + index; i++){
             state[index] = i;
             dfs(index+1, i+1);
        }
    }
    

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        
        state = new int[m+1];
        dfs(1, 1);
        
    }
}

AcWing1209. 带分数

import java.util.Scanner;

public class Main {

    static int n;

    static boolean[] used;

    static int count = 0;
    
    static int[] permutation;
    
    
    static int calc(int left, int right) {
        int result = 0;
        for(int i = left; i <= right; i++) {
            result = result * 10 + permutation[i];
        }
        return result;
    }
    

    static void dfs(int index){
        if(index > 9){
            for(int i = 1; i <= 7; i++){
                int a = calc(0, i);
                for(int j = i + 2; j <= 9; j++){
                    int b = calc(i+1, j-1);
                    int c = calc(j, 9);
                    if(n * c == a * c + b) ++count;
                }
            }
            return;
        }
        
        for(int i = 1; i <= 9; ++i){
            if(used[i]) continue;
            used[i] = true;
            permutation[index] = i;
            dfs(index+1);
            used[i] = false;
        }

    }

    public static void main(String[] args) {
         Scanner sc = new Scanner(System.in);
         n = sc.nextInt();
         used = new boolean[10];
         permutation = new int[10];
        
         dfs(1);
         System.out.println(count);
    }
}