【算法练习】Acwing第43周周赛

本周编程竞赛中,第一题通过暴力求解三元组来计算满足条件的组合数。第二题涉及数学推导,找到两个数列的交集区间并计算数量。第三题是高难度问题,利用离散化和树状数组解决合适数对问题。代码实现包括了数学逻辑和高效数据结构的应用。
摘要由CSDN通过智能技术生成


这周周赛拉了呀,后面两题都没AC...

一、三元组(简单、暴力)

在这里插入图片描述

import java.util.*;
import java.io.*;

public class Main {
	static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
	public static void main(String[] args) throws IOException {
		String[] input = reader.readLine().trim().split(" ");
		int n = Integer.parseInt(input[0]);
		int cnt = 0;
		for (int i = 1; i <= n; i++) {
			for (int j = i; j <= n; j++) {
				for (int k = j; k <= n; k++) {
					if (((i ^ j) ^ k) == 0 && (i + j > k) && (j + k > i) && (i + k > j)) cnt++;
				}
			}
		}
		System.out.println(cnt);
	}
}

二、两个数列(中等、数学推导)

在这里插入图片描述
想了半天,真没思路呀,难受心态崩了…

这道题就是找bi的上下界[bound, up],是一道数学题...

令 S r = S u m b − b i , b i = S u m b − S r , 令 S u m = ∑ i = 1 n a i 可 以 得 到 n − 1 < = S r < = S u m − a i − ( n − 1 ) > = − S r > = − ( S u m − a i ) S u m b − ( n − 1 ) > = S u m b − S r > = S u m b − ( S u m − a i ) , S u m b − S r 就 是 b i b i 还 有 上 下 界 : 1 < = b i < = a i , 我 们 求 两 个 不 等 式 的 交 集 数 , 再 用 a i − 所 有 可 能 取 值 就 可 以 得 到 不 能 取 的 数 量 令S_r =Sum_b - b_i,b_i = Sum_b - S_r,令Sum = \sum_{i = 1}^{n}a_i \\ 可以得到n - 1 <= S_r <= Sum - ai\\ -(n-1) >= -S_r >= - (Sum - a_i)\\ Sum_b-(n - 1) >= Sum_b - S_r >=Sum_b-(Sum_-a_i),Sum_b - S_r就是b_i \\ bi还有上下界:1 <= b_i <= a_i,我们求两个不等式的交集数,再用a_i - 所有可能取值 \\ 就可以得到不能取的数量 Sr=Sumbbibi=SumbSrSum=i=1nain1<=Sr<=Sumai(n1)>=Sr>=(Sumai)Sumb(n1)>=SumbSr>=Sumb(Sumai)SumbSrbibi1<=bi<=aiai

交集怎么求?
在这里插入图片描述
左端点的最大值,右端点的最小值即可。

import java.util.*;
import java.io.*;

public class Main {
	static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
	public static void main(String[] args) throws IOException {
		String[] input = reader.readLine().trim().split(" ");
		int n = Integer.parseInt(input[0]);
		long s = Long.parseLong(input[1]);
		int[] a = new int[n];
		long sum = 0L;
		input = reader.readLine().trim().split(" ");
		for (int i = 0; i < n; i++) {
			a[i] = Integer.parseInt(input[i]);
			// 求总和
			sum += a[i];
		}
		for (int i = 0; i < n; i++) {
			// get求交集区间长度
			if (i + 1 != n) {
				log.write(a[i] - get(1, a[i], s - (sum - a[i]), s - (n - 1)) + " ");
			} else {
				log.write(a[i] - get(1, a[i], s - (sum - a[i]), s - (n - 1)) + "");
			}
		}
		log.flush();
	}
	static long get(long a, long b, long c, long d) {
		// 左端点最大值,右端点最小值
		return Math.min(b, d) - Math.max(a, c) + 1;
	}
}

思路很简单,就是找不等式,但是没想到会成这样…一直想着用什么算法去做,太蠢了。

三、合适数对(困难、离散化、树状数组)

在这里插入图片描述
在这里插入图片描述
是一道离散化 + 树状数组的题目,java做离散化太麻烦了,下面就贴了y总的代码。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 400010;

int n;
LL m;
LL s[N], xs[N], cnt;
int tr[N];

int get(LL x)
{
    int l = 1, r = cnt;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (xs[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r;
}

int lowbit(int x)
{
    return x & -x;
}

void add(int x, int v)
{
    for (int i = x; i < N; i += lowbit(i))
        tr[i] += v;
}

int query(int x)
{
    int res = 0;
    for (int i = x; i; i -= lowbit(i))
        res += tr[i];
    return res;
}

int main()
{
    scanf("%d%lld", &n, &m);
    xs[ ++ cnt] = 0, xs[ ++ cnt] = -m;
    for (int i = 1; i <= n; i ++ )
    {
        int x;
        scanf("%d", &x);
        s[i] = s[i - 1] + x;
        xs[ ++ cnt] = s[i], xs[ ++ cnt] = s[i] - m;
    }

    sort(xs + 1, xs + cnt + 1);
    cnt = unique(xs + 1, xs + cnt + 1) - xs - 1;

    LL res = 0;
    add(get(0), 1);
    for (int i = 1; i <= n; i ++ )
    {
        res += i - query(get(s[i] - m));
        add(get(s[i]), 1);
    }

    printf("%lld\n", res);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@u@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值