Acwing第43周周赛
这周周赛拉了呀,后面两题都没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=Sumb−bi,bi=Sumb−Sr,令Sum=i=1∑nai可以得到n−1<=Sr<=Sum−ai−(n−1)>=−Sr>=−(Sum−ai)Sumb−(n−1)>=Sumb−Sr>=Sumb−(Sum−ai),Sumb−Sr就是bibi还有上下界:1<=bi<=ai,我们求两个不等式的交集数,再用ai−所有可能取值就可以得到不能取的数量
交集怎么求?
左端点的最大值,右端点的最小值即可。
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;
}