Contestant'. Rank 1390. Rating +9(+109 -100).

A. Divisible Array

题意

给定整数 \(n\),构造一个长度为 \(n\) 的数组 \(a\),满足 \(a_i \bmod i = 0\),且总和 \(sum\) 满足 \(sum \bmod n = 0\)

思路

构造一个 \(2, 4, \ldots, 2n\) 的数组,\(sum = \frac{(2 + 2n)n}{2} = n(n + 1)\)

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

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10;

void solve(){
    int n;
    cin >> n;
    for(int i=1;i<=n;i++) cout << i * 2 << ' ';
    cout << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

倒也有其他思路,这个最好写

B. Permutation Swap

题意

给定一个未排序的排列,输出最大的 \(k\),满足按照 "\(a_i\)\(a_{i + k}\)" 之间可交换的方式进行排序后,可将排列升序。

思路

如果一个数 \(x\) 位于 \(y\) 位置,他想要到 \(x\) 位置,那么 \(abs(y - x) \bmod k = 0\)

那么,如果所有数都要满足这个条件,我们只需求 \(gcd\) 即可。

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

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10;

void solve(){
    int n;
    cin >> n;
    int ans = -1;
    for(int i=1;i<=n;i++){
        int cur;
        cin >> cur;
        cur = abs(cur - i);
        if(cur == 0) continue;
        if(ans == -1) ans = cur;
        else ans = gcd(ans, cur);
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

瞎猜就完事了

C. Counting Orders

题意

给定两个长度相等的序列 \(a, b\),其中 \(a\) 中无重复元素,输出满足所有 \(a_i\) 均大于 \(b_i\)\(a\) 的所有排列的个数。

思路

我们将 \(a, b\) 升序排序,那么,对于每一个 \(a_i\),我们找出 \(b\) 中满足 \(a_i > b_i\) 的个数 \(cnt\),这个个数就是 \(a_i\) 能放的位置。

因而,答案就是 \(cnt_1 \cdot(cnt_2 - 1) \cdot(cnt_3 - 2) \cdots (cnt_n - (n - 1))\) (考虑前面几个数已经放了,而且前几个数能放的区间一定在当前能放的区间里面)。

找位置可以线性也可以二分。

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

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 1e9 + 7;

void solve(){
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for(int i=0;i<n;i++) cin >> a[i];
    for(int i=0;i<n;i++) cin >> b[i];
    sort(all(a)), sort(all(b));
    int ans = 0, cnt = 0;
    for(int i=n-1;i>=0;i--){
        int pos = n - (upper_bound(all(a), b[i]) - a.begin());
        if(pos <= cnt){
            cout << 0 << '\n';
            return;
        }
        if(ans == 0) ans = pos - cnt;
        else ans = (ans * (pos - cnt)) % mod;
        cnt ++;
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

乱猜即可

D1. Range Sorting (Easy Version)

题意

给定一个序列 \(p\),定义操作为选定一个区间 \([l, r]\),并将里面的数排序,代价为 \(r - l\)

输出对于序列的 所有连续子序列,任意次操作后,使其升序所需的最小代价的总和。

思路

首先,我们固定子序列的头,然后依次枚举尾。

不难发现,如果一段区间不需要参与排序,那么他一定是单调的,并且,除去这段区间后,没有比区间内的数小的数。

当然,这个区间内也不能包含比剩余数小的数。

我们维护一个单调栈,在弹出元素的时候,将元素和当前元素取最大值,最后放入栈中的是这个最大值。

这样即可满足上述的所有条件(比较抽象)。

取最大值是为了满足最后一个条件,而单调栈的维护满足了剩下的条件。

对于一段枚举的区间 \([i, j]\),最小代价就是 \(j - i - size\),其中 \(size\) 是单调栈的大小。

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

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define pci pair<char, int>
#define fs first
#define sc second
#define pb emplace_back
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, mod = 1e9 + 7;

void solve(){
    int n;
    cin >> n;
    vector<int> a(n);
    for(int i=0;i<n;i++) cin >> a[i];
    int ans = 0;
    for(int i=0;i<n;i++){
        stack<int> st;
        for(int j=i;j<n;j++){
            int mx = a[j];
            while(!st.empty() && a[j] < st.top()){
                mx = max(mx, st.top()), st.pop();
            }
            st.emplace(mx);
            ans += j - i + 1 - st.size();
        }
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t --) solve();
}

太妙了!