Codeforces Round #760 (Div. 3) A~G题解

A. Polycarp and Sums of Subsequences

题目

​ 给我们一个长度为 3 3 3 的正整数数组 a a a b b b 是一个长度为 7 7 7 的数组, b b b 中的每个元素代表着数组 a a a 某个子序列的元素和。

​ 例如 a a a 数组等于 { 1 , 4 , 3 } \{1,4,3\} {1,4,3} , 那么 b = { 1 , 3 , 4 , 1 + 3 , 1 + 4 , 3 + 4 , 1 + 3 + 4 } = { 1 , 3 , 4 , 4 , 5 , 7 , 8 } b = \{1, 3, 4, 1 + 3, 1 + 4, 3 + 4, 1 + 3 + 4\} = \{1,3,4,4,5,7,8\} b={1,3,4,1+3,1+4,3+4,1+3+4}={1,3,4,4,5,7,8}

​ 现在给出一个数组 b b b ( b i < b i + 1 b_i < b_{i + 1} bi<bi+1 0 ≤ b i ≤ 1 0 9 0≤b_i≤10^9 0bi109 ) , 求一组满足条件的数组 a a a

知识点

思维

解题思路

​ 我们假设数组 a a a 满足 a 1 ≤ a 2 ≤ a 3 a_1 ≤ a_2 ≤ a_3 a1a2a3

​ 由于 a i > 0 a_i > 0 ai>0 , 那么必定会有 a 1 = b 1 a_1 = b_1 a1=b1 a 2 = b 2 a_2 = b_2 a2=b2 a 1 + a 2 + a 3 = b 7 a1+a2+a3 = b_7 a1+a2+a3=b7

​ 所以我们只需要输出 b 1 , b 2 , b 7 − b 1 − b 3 b_1, b_2, b_7 - b_1 - b_3 b1,b2,b7b1b3 就行了。

代码
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << '\n'
#define between(x, l, r) (x >= l && x <= r)
#define point(a, b, m) ((a - 1) * m + b)
#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define np next_permutation
#define lb lower_bound
#define ub upper_bound
#define eb emplace_back
#define pb push_back
#define y second
#define x first
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

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

int n, m;
int a[N], b[N];

void solve()
{
    for (int i = 1; i <= 7; i ++ ) cin >> b[i];
    cout << b[1] << ' ' << b[2] << ' ' << b[7] - b[1] - b[2] << '\n';
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cout.precision(2), cout.setf(ios::fixed);
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

B. Missing Bigram

题目

在这里插入图片描述

知识点

思维

解题思路

​ 由于题目是按照顺序给我们的,并且保证了题目有解,所以我们只要顺序遍历过去,如果第 i − 1 i - 1 i1 个单词的末尾不等于第 i i i 个单词的开头,那就说明是在这删除了一个单词,我们补回来就行了。 如果全都是对应的上的,那就在最后加一个字母 a a a

(详细见代码)

代码
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << '\n'
#define between(x, l, r) (x >= l && x <= r)
#define point(a, b, m) ((a - 1) * m + b)
#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define np next_permutation
#define lb lower_bound
#define ub upper_bound
#define eb emplace_back
#define pb push_back
#define y second
#define x first
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

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

int n, m;
string s, ans;

void solve()
{
    int n;
    cin >> n;
    cin >> ans;
    bool f = 0;
    for (int i = 2; i <= n - 2; i ++ )
    {
        int num = ans.size();
        cin >> s;
        if(ans[num - 1] != s[0])
        {
            ans.push_back(s[0]);
            f = 1;
        }
        ans.push_back(s[1]);
    }

    if(!f) ans.push_back('a');
    cout << ans << '\n';
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cout.precision(2), cout.setf(ios::fixed);
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

C. Paint the Array

题目

在这里插入图片描述

知识点

思维,数论

解题思路

​ 由题意可知,我们要选择一个数 d d d, 使得数组 a a a 的奇数位和偶数位中,其中一个全都被 d d d 整除,另一个全都不被 d d d 整除。

​ 那么我们可以分别判断数组 a a a 的奇数位被 d d d 整除,和偶数位被 d d d 整除是否存在,如果两个都不存在,那么输出 0 0 0

​ 我们拿奇数位被 d d d 整除为例, 我们设 d = p 1 x 1 ∗ p 2 x 2 ∗ p 3 x 3 ∗ . . . ∗ p k x k d = p_1^{x1}*p_2^{x2}*p_3^{x3}*...*p_k^{x_k} d=p1x1p2x2p3x3...pkxk ( p i p_i pi 是质数), 且对于 ∀ i ∈ { x ∣ x = 2 ∗ k − 1 , k ∈ N ∗ } ∀i∈\{x|x = 2*k - 1, k ∈N^*\} i{xx=2k1,kN} 满足 d ∣ a i d | a_i dai

​ 我们再设一个数 X = p 1 x 1 ′ ∗ p 2 x 2 ′ ∗ p 3 x 3 ′ ∗ . . . ∗ p k x k ′ X = p_1^{x1'}*p_2^{x2'}*p_3^{x3'}*...*p_k^{x_k'} X=p1x1p2x2p3x3...pkxk, 只要存在 i i i 满足 x i > x i ′ x_i > x_i' xi>xi, 那么 X X X 将不被 d d d 整除。

​ 因此我们最大化每个 x i x_i xi一定是最优的, 所以我们令 d = g c d ( a 1 , a 3 , a 5 , . . . ) d = gcd(a_1, a_3, a_5,...) d=gcd(a1,a3,a5,...), 然后检测 a 2 , a 4 , a 6 , . . . a_2, a_4,a_6,... a2,a4,a6,... 是否被 d d d 整除, 偶数位同理。

(详细见代码)

代码
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << '\n'
#define between(x, l, r) (x >= l && x <= r)
#define point(a, b, m) ((a - 1) * m + b)
#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define np next_permutation
#define lb lower_bound
#define ub upper_bound
#define eb emplace_back
#define pb push_back
#define y second
#define x first
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

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

int n, m;
LL a[N];
/*
能整除
不能整除
能
不能
*/

void solve()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];

    LL Gcd = a[1];
    for (int i = 3; i <= n; i += 2)
    {
        Gcd = __gcd(Gcd, a[i]);
    }

    for (int i = 2; i <= n; i += 2)
    {
        if(a[i] % Gcd == 0)
        {
            Gcd = 1;
            break;
        }
    }

    if(Gcd != 1)
    {
        cout << Gcd << '\n';
        return;
    }

    Gcd = a[2];
    for (int i = 4; i <= n; i += 2)
    {
        Gcd = __gcd(Gcd, a[i]);
    }

    for (int i = 1; i <= n; i += 2)
    {
        if(a[i] % Gcd == 0)
        {
            Gcd = 1;
            break;
        }
    }

    if(Gcd != 1)
    {
        cout << Gcd << '\n';
        return;
    }

    cout << 0 << '\n';
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cout.precision(2), cout.setf(ios::fixed);
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

D. Array and Operations

题目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-le650HQf-1639636755690)(C:\Users\hunzia\AppData\Roaming\Typora\typora-user-images\image-20211216112735519.png)]

知识点

思维

解题思路

​ 对于该题我们先对 a a a 数组升序排序,我们可以证明删去最大的 2 k 2k 2k 个数一定是最优的。

口胡证明部分:

​ 因为我们在选择这 k k k ( i , j ) (i, j) (i,j) 时一定会选 a i ≤ a j a_i ≤ a_j aiaj 的情况,所以一对(i, j)的贡献最多为1,而我们删去 a i a_i ai , a j a_j aj 时对答案的贡献是 − ( a i + a j ) -(a_i+a_j) (ai+aj) ,假如一开始我 a i = a j a_i = a_j ai=aj ,贡献 a d d 1 = 1 − ( a i + a j ) add1 = 1 - (a_i+a_j) add1=1(ai+aj) 。如果我将 a i a_i ai 改为 a k a_k ak ( a k < a i a_k < a_i ak<ai), 那么贡献 a d d 2 = − ( a j + a k ) = − ( a j + a i + ( a k − a i ) ) = − ( a i + a j ) + ( a i − a k ) ≥ a d d 1 add2 = -(a_j + a_k) = -(a_j + a_i + (a_k - a_i)) = -(a_i + a_j) + (a_i - a_k) ≥ add1 add2=(aj+ak)=(aj+ai+(akai))=(ai+aj)+(aiak)add1 ,由于我们要最小化分数,所以我们选择最大的 2 k 2k 2k 个数删去一定是最优的。

​ 在选择了应该删去的 2 k 2k 2k 个数后,我们要考虑如何使得这 k k k ( i , j ) (i, j) (i,j) ⌊ a i a j ⌋ \lfloor \frac{a_i}{aj} \rfloor ajai 的结果最小。在观察一下之后我们可以知道, 这个结果只和某个值在这 2 k 2k 2k 个数中出现的次数有关,如果一个数 x x x 在这 2 k 2k 2k 个数中出现的次数 n u m [ x ] > k num[x]>k num[x]>k , 那么这 2 k 2k 2k 个数的 ⌊ a i a j ⌋ \lfloor \frac{a_i}{aj} \rfloor ajai 的和就等于 ⌊ n u m [ x ] − k 2 ⌋ \lfloor\frac{num[x] - k}{2}\rfloor 2num[x]k,否则我们可以通过相互匹配的方式来将所有数的 ⌊ a i a j ⌋ \lfloor \frac{a_i}{aj} \rfloor ajai 变为0。

(详细见代码)

代码
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << '\n'
#define between(x, l, r) (x >= l && x <= r)
#define point(a, b, m) ((a - 1) * m + b)
#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define np next_permutation
#define lb lower_bound
#define ub upper_bound
#define eb emplace_back
#define pb push_back
#define y second
#define x first
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

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

int n, m;
int a[N];
int cnt[N];

void solve()
{
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
    sort(a + 1, a + n + 1);
    LL res = 0;
    for (int i = 1; i <= n - 2 * k; i ++ ) res += a[i];

    //这里最小化1的数量
    int Max = 0;
    for (int i = n - 2 * k + 1; i <= n; i ++ ) cnt[a[i]] ++ , Max = max(cnt[a[i]], Max);
    for (int i = n - 2 * k + 1; i <= n; i ++ ) cnt[a[i]] -- ;
    res += max(0, (Max - (2 * k - Max)) / 2);
    cout << res << '\n';
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cout.precision(2), cout.setf(ios::fixed);
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

E. Singers’ Tour

题目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zp6s09Qb-1639636755691)(C:\Users\hunzia\AppData\Roaming\Typora\typora-user-images\image-20211216115459807.png)]

知识点

思维

解题思路

​ 由题意可知

b i = 1 ∗ a i + 2 ∗ a i − 2 % n + 1 + 3 ∗ a i − 3 % n + 1 + . . . + n ∗ a i % n + 1 b_i = 1 * a_i + 2 * a_{i-2\% n+1} + 3 * a_{i-3\% n+1} + ... + n * a_{i\%n+1} bi=1ai+2ai2%n+1+3ai3%n+1+...+nai%n+1

​ 所以我们有 s u m = b 1 + b 2 + b 3 + . . . + b n ( n + 1 ) ∗ n / 2 sum = \frac{b_1+b_2+b_3+...+bn}{(n+1)*n/2} sum=(n+1)n/2b1+b2+b3+...+bn b i − b i − 1 = s u m − n ∗ a i b_i - b_{i - 1} = sum - n * a_i bibi1=sumnai

​ 所以我们有 a i = s u m + b [ i − 1 ] − b [ i ] n a_i = \frac{sum + b[i - 1] - b[i]}{n} ai=nsum+b[i1]b[i]

(详细见代码)

代码
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << '\n'
#define between(x, l, r) (x >= l && x <= r)
#define point(a, b, m) ((a - 1) * m + b)
#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define np next_permutation
#define lb lower_bound
#define ub upper_bound
#define eb emplace_back
#define pb push_back
#define y second
#define x first
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

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

LL a[N], b[N];

void solve()
{
    LL n;
    cin >> n;
    LL tot = 0;
    for (int i = 1; i <= n; i ++ )
    {
        cin >> b[i];
        tot += b[i];
    }

    if(tot % (n * (n + 1) / 2) != 0)
    {
        cout << "NO\n";
        return;
    }

    LL suma = tot / (n * (n + 1) / 2);

    for (int i = 1; i <= n; i ++ )
    {
        if( (suma + b[(i - 2 + n) % n + 1] - b[i]) % n || (suma + b[(i - 2 + n) % n + 1] - b[i]) <= 0)
        {
            cout << "NO\n";
            return;
        }

        a[i] = (suma + b[(i - 2 + n) % n + 1] - b[i]) / n;
    }

    cout << "YES\n";
    for (int i = 1; i <= n; i ++ ) cout << a[i] << ' ';
    cout << '\n';
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cout.precision(2), cout.setf(ios::fixed);
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

F. Reverse

题目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GF1lCk2c-1639636755693)(C:\Users\hunzia\AppData\Roaming\Typora\typora-user-images\image-20211216120414650.png)]

知识点

思维,暴力

解题思路

​ 我们令 B B B b b b 的二进制表示, A 1 A_1 A1 a a a 的二进制表示, A 2 A_2 A2 A 1 A_1 A1 的翻转, A 3 A_3 A3 A 1 A_1 A1 去掉后缀零, A 4 A_4 A4 A 1 A_1 A1 后面加一个 1 再翻转的结果。(这里的 B B B, A 1 A1 A1, A 2 A2 A2, A 3 A3 A3 , A 4 A4 A4 都不带前导零)

​ 通过观察我们可以发现 我们只要判断 B B B 是否是 1..1 A 1 1...1 1..1A_11...1 1..1A11...1, 1..1 A 2 1...1 1..1A_21...1 1..1A21...1 1..1 A 3 1...1 1..1A_31...1 1..1A31...1 1..1 A 4 1...1 1..1A_41...1 1..1A41...1 中的一个就行(前后的 1 1 1 的个数可以为 0 0 0 ),如果都不是就输出 NO 。( A 1 A_1 A1 需要特判是否最后一个字符为0, 如果是的话,那么 1...1 A 1 1...1A_1 1...1A1 这种前面有 1 1 1, 后面无 1 1 1 的形式是不行的)

(详细见代码)

代码
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << '\n'
#define between(x, l, r) (x >= l && x <= r)
#define point(a, b, m) ((a - 1) * m + b)
#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define np next_permutation
#define lb lower_bound
#define ub upper_bound
#define eb emplace_back
#define pb push_back
#define y second
#define x first
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
 
const int N = 3e5 + 10, M = 2 * N, mod = 1e9 + 7;
 
int n;
string t;
int flag = 1;
 
void f(string &s) // 去掉前导零
{
    string tmp;
 
    bool f = 1;
    for (auto & it : s)
    {
        if(f && it == '0') continue;
        f = 0;
        tmp.push_back(it);
    }
    s = tmp;
}
 
bool func(string s)
{
    if(t == s) return 1;
    if(t.size() < s.size()) return 0;
 
    if(!(t.size() > s.size() && s[s.size() - 1] == '0')) flag = 0;
 
    for (int i = 0; i <= n - s.size() - flag; i ++ )
    {
        if(t.substr(i, s.size()) == s)
        {
            bool f = 1;
            for (int j = i + s.size(); j < n; j ++ )
            {
                if(t[j] == '0')
                {
                    f = 0;
                    break;
                }
            }
 
            if(f) return 1;
        }
 
        if(t[i] == '0') return 0;
    }
 
    flag = 0;
    return 0;
}
 
void solve()
{
    LL x, y;
    cin >> x >> y;
    bitset<100> bit1(x), bit2(y);
    string s = bit1.to_string();
    t = bit2.to_string();
 
    f(t), f(s);
    n = t.size();
 
    //正
    if(func(s))
    {
        cout << "YES\n";
        return;
    }
 
    //反
    string tmp = s;
    reverse(all(tmp));
    f(tmp);
 
    if(func(tmp))
    {
        cout << "YES\n";
        return;
    }
 
    // +1 翻转
    tmp = s;
    tmp += '1';
    reverse(all(tmp));
 
    if(func(tmp))
    {
        cout << "YES\n";
        return;
    }
 
    // 去后缀0
    tmp = s;
    reverse(all(tmp));
    f(tmp);
    reverse(all(tmp));
 
    if(func(tmp))
    {
        cout << "YES\n";
        return;
    }
 
    cout << "NO\n";
}
 
int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cout.precision(2), cout.setf(ios::fixed);
    // int t;
    // cin >> t;
    // while (t -- )
    solve();
    return 0;
}

G. Trader Problem

题目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6LWCwtfN-1639636755694)(C:\Users\hunzia\AppData\Roaming\Typora\typora-user-images\image-20211216131520613.png)]

知识点

思维,并查集,贪心,前缀和,离线处理

解题思路

​ 观察了一下,我们发现题目其实可以转化为

​ 数组 c c c 中选择 n n n 个数(初始我们已经选了 n n n 个数,我们可以通过某种操作将其改选为其他的数),求被选中的数的和的最大值。( c = a + b c = a + b c=a+b, 长度为 n + m n + m n+m )

​ 假设初始给我们的 n n n 个数(数组 a a a 中的数) 的下标分别为 p 1 , p 2 , p 3 , . . . , p n p_1, p_2, p_3,...,p_n p1,p2,p3,...,pn , 我们一次操作可以将 p i p_i pi 改为 x x x 当且仅当 ∣ c p i − c x ∣ ≤ k |c_{p_i}-c_x| ≤ k cpicxk x ≠ p j , j ∈ [ 1 , n ] x ≠ p_j, j∈[1, n] x=pj,j[1,n], 我们很容易发现这种修改是具有可传递性的,既如果 i i i 可以改成 j j j , j j j 可以改成 t t t,那么 i i i 就能改成 t t t。所以我们可以将所有能通过修改来到达的位置用一个集合来维护。如果集合中有 n u m num num 个数处于被选择状态,那么我们将这 n u m num num 个数改为该集合中最大的 n u m num num 个数一定是最优的。

​ 然后我们考虑怎么去维护集合中的前 n u m num num 大的数的和。我们先将数组 c c c 升序排序, 我们很容易就可以发现集合中的元素在数组 c c c 中都是连续, 比如 k = 3 , c = [ 1 , 3 , 4 , 5 , 9 , 13 , 13 , 15 ] k = 3, c = [1, 3, 4, 5, 9, 13, 13, 15] k=3,c=[1,3,4,5,9,13,13,15] 那么该数组中的集合为 [ 1 , 3 , 4 , 5 ] , [ 9 ] , [ 13 , 13 , 15 ] [1, 3, 4, 5],[9],[13,13,15] [1,3,4,5],[9],[13,13,15] , 所以我们只要让集合的编号等于它最大的元素的下标 M a x I d x MaxIdx MaxIdx 就行了, 集合中前 n u m num num 大的数的和就是 c [ M a x I d x ] + c [ M a x I d x − 1 ] + . . . + c [ M a x I d x − n u m + 1 ] c[MaxIdx] + c[MaxIdx - 1] + ... + c[MaxIdx - num +1] c[MaxIdx]+c[MaxIdx1]+...+c[MaxIdxnum+1] ,这个我们可以通过前缀和数组 O ( 1 ) O(1) O(1) 得出。

​ 最后我们离线后,按照 k k k 从小到大处理这 q q q 次询问。

(详细见代码)

代码
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x << '\n'
#define between(x, l, r) (x >= l && x <= r)
#define point(a, b, m) ((a - 1) * m + b)
#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define np next_permutation
#define lb lower_bound
#define ub upper_bound
#define eb emplace_back
#define pb push_back
#define y second
#define x first
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

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

int n;
int a[N], b[N], c[N]; 
LL s[N], ans[N], res;
int fa[N], siz[N];
PII p[N];

struct Query
{
    int id, k;
} q[N];

int find(int x) //并查集
{
    if(fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}

void merge(int x)
{
    auto &[d, pos] = p[x];
    int pa = find(pos), pb = find(pos + 1);
    
    //先减去原集合的贡献
    res -= s[pa] - s[pa - siz[pa]] + s[pb] - s[pb - siz[pb]];
    
    siz[pb] += siz[pa];
    fa[pa] = pb;
    
    //加上合并后的集合的贡献
    res += s[pb] - s[pb - siz[pb]];
}

void solve()
{
    int n, m, Q;
    cin >> n >> m >> Q;
    
    for (int i = 1; i <= n; i ++ ) cin >> a[i], c[i] = a[i], res += a[i];
    for (int i = 1; i <= m; i ++ ) cin >> b[i], c[i + n] = b[i];

    sort(a + 1, a + n + 1);
    sort(c + 1, c + n + m + 1);
	
    // p[i]为c[i + 1]到c[i]之间的差值
    for (int i = 1; i < n + m; i ++ )
    {
        p[i] = {c[i + 1] - c[i], i};
    }
	
    // 初始化并查集, Siz[i]代表编号为i的集合中被选中的数的数量
    for (int i = 1, j = 1; i <= n + m; i ++ )
    {
        fa[i] = i;
        if(j <= n && c[i] == a[j])
        {
            siz[i] = 1;
            j ++ ;
        }
    }
	
    //将p按照差值从小到大排序
    sort(p + 1, p + n + m);
	
    for (int i = 1; i <= Q; i ++ )
    {
        int k;
        cin >> k;
        q[i] = {i, k};
    }
	
    // 将q按照给的k从小到大排序
    sort(q + 1, q + Q + 1, [&](Query a, Query b){ return a.k < b.k;});
	
    //前缀和
    for (int i = 1; i <= n + m; i ++ ) s[i] = s[i - 1] + c[i];
	
    //从小到大遍历 k
    for (int i = 1, pos = 0; i <= Q; i ++ )
    {
        auto &[id, k] = q[i];
        // 只要p[pos]的差值小于等于k, 那么就合并pos,pos+1所在的集合 
        while (pos < n + m - 1 && p[pos + 1].x <= k) merge( ++ pos);
        ans[id] = res;
    }

    for (int i = 1; i <= Q; i ++ ) cout << ans[i] << '\n';
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cout.precision(2), cout.setf(ios::fixed);
    // int t;
    // cin >> t;
    // while (t -- )
    solve();
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值