Practice.

A. Joey Takes Money

题意

给定一个包含 \(n\)\(\geq 1\) 的元素的数组 \(a\),定义操作为:

  1. 选定 \(i, j, i \neq j\)
  2. 选两个 \(\geq 1\) 的正整数 \(x, y\),满足 \(x \cdot y = a_i \cdot a_j\)
  3. \(a_i, a_j\) 改为 \(x, y\)

输出任意次操作后数组的和的最大值 x2022

思路

显然,对于 \(a_i, a_j\)\(1 + a_i \cdot a_j\) 一定是所有操作中最大的和,那么我们可以依次从左到右将所有数都执行一遍该操作,得到 \(1, 1, 1, \ldots, \prod a_i\),求和即可。

时间复杂度:\(O(n)\)

对应AC代码

import java.util.*;

public class Main{

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt();
        while(t-- > 0){
            int n = scanner.nextInt();
            long[] a = new long[n];
            for(int i=0;i<n;i++) a[i] = scanner.nextInt();
            Arrays.sort(a);
            for(int i=0;i<n-1;i++){
                a[n - 1] = a[n - 1] * a[i];
                a[i] = 1;
            }
            System.out.println(2022 * ((long) (n - 1) + a[n - 1]));
        }
    }
}

简单思维题 & 2022x1

B. Kill Demodogs

题意

给定一个 \(n \times n\) 的矩阵,\((i, j)\) 位置的元素值为 \(i \times j\)。定义人物从 \((1, 1)\) 走到 \((n, n)\),期间人物只能向下或向右移动一格,输出到达终点后经过的元素的值的总和的最大值。

思路

显然,我们走对角线是最优的,此时横坐标和纵坐标的值最相近。

此时,我们可以得到下面的式子:

\(1 \times 1 + 1 \times 2 + 2 \times 2 + \ldots + (n - 1) \times n + n \times n\)

我们将其拆成两个式子:

  1. \(1 \times 1 + 2 \times 2 + \ldots + n \times n\)
  2. \(1 \times 2 + 2 \times 3 + \ldots + (n - 1) \times n\)

对于上述两个式子,我们套用公式即可。

最后,我们可以得到下面的式子:

\(\frac{n (n + 1) (2n + 1)}{6} + \frac{(n - 1) n (n + 1)}{3}\)

此时,我们有两个选择:大数或者逆元。任选其一即可。

时间复杂度:\(O(1)?\)

对应AC代码

import java.math.BigInteger;
import java.util.*;

public class Main{

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt(), mod = 1000000007;
        while(t -- > 0){
            long n = scanner.nextInt();
            System.out.println((2022 *
                    ((BigInteger.valueOf(n).multiply(BigInteger.valueOf(n + 1)).multiply(BigInteger.valueOf(2 * n + 1)).divide(BigInteger.valueOf(6)).mod(BigInteger.valueOf(mod)).longValue() +
                            BigInteger.valueOf(n - 1).multiply(BigInteger.valueOf(n)).multiply(BigInteger.valueOf(n + 1)).divide(BigInteger.valueOf(3)).mod(BigInteger.valueOf(mod)).longValue()) % mod)) % mod);
        }
    }
}

大数yyds

C. Even Subarrays

题意

给定一个长度为 \(n\) 的数组 \(a\)\(1 \leq a_i \leq n\),输出连续的子序列的个数,子序列需满足子序列的异或值有偶数个因数。

思路

这里需要用到一个性质:只有完全平方数的因数数量是奇数。

所以,我们不妨找完全平方数,然后取一个补集即可。

考虑到异或的交换性,我们不妨用答案来枚举。

更具体地说,我们不妨从前向后遍历,\(cur\) 为前 \(i\) 个元素的异或值,我们用 \(m\) 数组存储这些异或值出现的次数,然后,我们枚举所有可能的答案,算出 \(cur\) 需要和 前面的哪一段区间的异或值 进行异或后得到完全平方数,用类似于前缀和的方式记录答案。

考虑到 \(a_i\) 的范围,我们只需枚举 \(2n\) 及以下的完全平方数即可。

时间复杂度:\(O(n \sqrt n)\)

对应AC代码

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt();
        while(t -- > 0){
            int n = scanner.nextInt();
            int[] a = new int[n];
            for(int i=0;i<n;i++) a[i] = scanner.nextInt();
            long[] m = new long[2 * n];
            int cur = 0;
            long cnt = 0;
            m[cur] = 1;
            for(int i=0;i<n;i++){
                cur ^= a[i];
                for(int j=0;j*j<2*n;j++){
                    int now = cur ^ (j * j);
                    if(now < 2 * n) cnt += m[now];
                }
                m[cur] ++;
            }
            System.out.println((long) n * (n - 1) / 2 + n - cnt);
        }
    }

}

异或的性质太多力