AcWing 1236. 递增三元组(枚举 + 二分||前缀和)

Problem

这个题的数据量比较大,单纯的暴力是O(n3),次数会达到1015,这是在搞笑,得亏蓝桥是OI赛制,否则这个题AC个人觉得是比较困难的,但是经过学习提示以后这个题也不难,主要就是

枚举b这个数组,因为如果枚举a,b和c的关系不稳定,需要再一层枚举去控制b和c的关系(枚举c的道理一样),所以首先想到枚举b以后优化a和c,具体优化方法有2个,二分法和前缀和法。

第一个方法二分,需要将三个数组排序,利用二分logN的速度拿到a和c分别的上下限,然后计算得出。
第二个是前缀和,利用cnt[]数组,下标的含义是下标这个值在a和c中出现的次数,然后用s[]统计出cnt的前缀和,相当于某个阈值以内数的总和,很巧妙的方法。

方法一: 二分法

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;

class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(System.out);

    public static void main(String[] args) throws IOException {
        String ss[] = br.readLine().split(" ");
        int n = Integer.parseInt(ss[0]);
        int a[] = new int[n];
        int b[] = new int[n];
        int c[] = new int[n];
        ss = br.readLine().split(" ");
        for (int i = 0; i < n; i++) a[i] = Integer.parseInt(ss[i]);

        ss = br.readLine().split(" ");
        for (int i = 0; i < n; i++) b[i] = Integer.parseInt(ss[i]);

        ss = br.readLine().split(" ");
        for (int i = 0; i < n; i++) c[i] = Integer.parseInt(ss[i]);

        Arrays.sort(a);
        Arrays.sort(b);
        Arrays.sort(c);

        long res = 0;
        int left, right;
        for (int i = 0; i < n; i++) {
            int l = 0, r = n - 1;
            while (l < r) {
                int mid = l + r + 1 >> 1;
                if (a[mid] < b[i]) l = mid;
                else r = mid - 1;
            }
            if (a[l] >= b[i]) l = -1;
            left = l;
            l = 0;
            r = n - 1;
            while (l < r) {
                int mid = l + r >> 1;
                if (c[mid] > b[i]) r = mid;
                else l = mid + 1;
            }
            if (b[i] >= c[r]) r = n;
            right = r;
            res += ((long) (n - right) * (left + 1));
        }
        pw.print(res);

        pw.flush();
        pw.close();
        br.close();
    }
}

方法二:前缀和

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;

class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(System.out);
    static int N = 100010;
    static int a[] = new int[N], b[] = new int[N], c[] = new int[N];
    static int cnt[] = new int[N], s[] = new int[N];
    static int as[] = new int[N], cs[] = new int[N];

    public static void main(String[] args) throws IOException {
        String ss[] = br.readLine().split(" ");
        int n = Integer.parseInt(ss[0]);

        ss = br.readLine().split(" ");
        for (int i = 0; i < n; i++) {
            a[i] = Integer.parseInt(ss[i]);
            a[i]++;
        }
        ss = br.readLine().split(" ");
        for (int i = 0; i < n; i++) {
            b[i] = Integer.parseInt(ss[i]);
            b[i]++;
        }
        ss = br.readLine().split(" ");
        for (int i = 0; i < n; i++) {
            c[i] = Integer.parseInt(ss[i]);
            c[i]++;
        }

        for (int i = 0; i < n; i++) cnt[a[i]]++;
        for (int i = 1; i < N; i++) s[i] = s[i - 1] + cnt[i];
        for (int i = 0; i < n; i++) as[i] = s[b[i] - 1];

        Arrays.fill(cnt, 0);
        Arrays.fill(s, 0);
        for (int i = 0; i < n; i++) cnt[c[i]]++;
        for (int i = 1; i < N; i++) s[i] = s[i - 1] + cnt[i];
        for (int i = 0; i < n; i++) cs[i] = s[N - 1] - s[b[i]];

        long res = 0;
        for (int i = 0; i < n; i++) res += (long) as[i] * cs[i];
        pw.print(res);

        pw.flush();
        pw.close();
        br.close();
    }
}
发布了167 篇原创文章 · 获赞 3 · 访问量 3428

猜你喜欢

转载自blog.csdn.net/qq_43515011/article/details/104284601