Practice.

A. SSeeeeiinngg DDoouubbllee

题意

给定一个字符串,将字符串复制一遍后拼接在一起得到一个新的字符串,将该字符串重新组合,输出一种回文组合。

思路

倒着拼到末尾。

时间复杂度:\(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){
            String s = scanner.next();
            System.out.println(s + new StringBuilder(s).reverse());
        }
    }
}

过于无脑

B. XOR = Average

题意

给定一个整数 \(n\),构造一个长度为 \(n\) 的无重复元素的数组 \(a\),满足 \(1 \leq a \leq 10 ^ 9\) 以及所有数的异或值等于平均值,即

\(a_1 \oplus a_2 \oplus \dots \oplus a_n = \frac{a_1 + a_2 + \dots + a_n}{n}\)

输出数组的任意一种构造。

思路

我们来考虑奇偶性:

  1. \(n\) 为奇数时,我们只需输出 \(n\)\(1\),此时恰好满足条件;

  2. \(n\) 为偶数时,考虑到 \(1, 3\) 的平均数为 \(2\),异或值也为 \(2\),而偶数个相同数的异或值为 \(0\),所以我们不妨输出 \(1,3\),以及 \(n - 2\)\(2\),即可满足条件。

时间复杂度:\(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();
            if(n % 2 == 1){
                for(int i=0;i<n;i++) System.out.print("1 ");
                System.out.println();
            }else{
                System.out.print("1 3 ");
                for(int i=0;i<n-2;i++) System.out.print("2 ");
                System.out.println();
            }
        }
    }
}

小的就足矣

C. Almost All Multiples

题意

给定整数 \(n, x\),构建一个字典序最小的排列 \(p\),满足下面的条件:

  1. \(p_1 = x, p_n = 1\)

  2. \(p_i \% i = 0\)

思路

显然,若不考虑条件,那么我们肯定会输出一个递增的排列。

当我们考虑条件后,我们不难发现 \(n\) 多余了,而 \(x\) 所在的原位置留空了。

但是,我们不可以直接将 \(x\) 的位置放上 \(n\),因为我们需要考虑下面的两个条件:

  1. \(p_x = n \rightarrow n \% x\)

  2. 字典序最小

对于条件 \(1\),若不满足,输出 \(NO\) 即可。

对于条件 \(2\),我们不难发现,当 \(n\) 的因数比较多的时候,满足 \(n \% kx\)\(k\) 可以有好多个,此时若 \(x\) 位置放上 \(n\),所得到的字典序不一定是最小的。

我们来举一个例子:

1
12 2

此时,字典序最小的应为下述输出:

2 4 3 12 5 6 7 8 9 10 11 1

因此,我们不妨循环操作,对于 \(x\),找出第一个满足 \(n \% kx, k \geq 2\)\(k\),将 \(p_i\) 修改为 \(kx\)\(x\) 的值替换为 \(kx\) ,然后继续循环,直到 \(x \geq x\)

时间复杂度:不知道

对应AC代码

#include<bits/stdc++.h>

using namespace std;

#define int long long

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while(t --){
        int n, x;
        cin >> n >> x;
        if(n % x != 0) cout << -1 << '\n';
        else{
            vector<int> ans(n);
            for(int i=1;i<n-1;i++) ans[i] = i + 1;
            ans[n - 1] = 1;
            ans[0] = x;
            while(x < n){
                for(int i=x*2;i<=n;i+=x) {
                    if(n % i == 0){
                        ans[x - 1] = i;
                        x = i;
                        break;
                    }
                }
            }
            for(int i=0;i<n;i++) cout << ans[i] << ' ';
            cout << '\n';
        }
    }
    return 0;
}

一开始还真想着去直接交换了(

D. Range = √Sum

题意

给定一个整数 \(n\),构建一个无重复元素的数组 \(a\),满足 \(1 \leq a_i \leq 10 ^ 9\),以及下面的式子:

\(\max(a_1, a_2, \dots, a_n) - \min(a_1, a_2, \dots, a_n)= \sqrt{a_1 + a_2 + \dots + a_n}\)

思路

我们来讨论 \(n\) 的奇偶性:

  1. \(n\) 为偶数的时候,我们只需构建一个 \([n / 2, n / 2 + 1, \ldots, n - 1, n + 1, n + 2, \ldots, 3n / 2]\) 即可。

  2. \(n\) 为奇数的时候,我们按照上述逻辑构建一个中间值为 \(n\),向两端递减 \(1\) 的数组,此时,左边为 \(n\),右边为 \(\sqrt {n (n + 1)}\)。 那么,我们希望构建一个数组,满足左右两边均为 \(n + 1\)。 我们执行下面的操作: ① 整个数组 \(+1\); ② 左边界 \(-1\),右边界 \(+1\); ③ 倒数第二个数 \(+1\)

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

对应AC代码

#include<bits/stdc++.h>

using namespace std;

#define int long long

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while(t --){
        int n;
        cin >> n;
        if(n % 2 == 0) {
            for(int i=n/2;i<=n-1;i++) cout << i << ' ';
            for(int i=n+1;i<=3*n/2;i++) cout << i << ' ';
        }
        else {
            vector<int> ans(n);
            iota(ans.begin(), ans.end(), (n + 5) / 2);
            ans[0]--;
            ans[n - 1]++;
            ans[n - 2]++;
            for (int i = 0; i < n; i++) cout << ans[i] << ' ';
        }
        cout << '\n';
    }
    return 0;
}

好一个思维 + 构造