Deltix Round, Automn 2021(Div.1 + Div.2)

Deltix Round, Automn 2021

A. Divide and Multiply

题意

给定 \(n\) 个数字,每次可以选择其中两个数字(其中一个为偶数),把其中的一个偶数除以 \(2\) ,另一个数字乘以 \(2\) ,问若干次操作后,这 \(n\) 个数字的最大和为多少。

分析

把所有的 \(2\) 提取出来,再放到最大的数字上去。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define rep(i, x, y) for(int i = x; i <= y; i++)
#define int long long
using namespace std;
const int N = 200010;

int a[N];

void solve ()
{
    int n; cin >> n;
    int ans = 0, cnt = 0;
    rep(i, 1, n)
    {
        cin >> a[i];
        while(a[i] % 2 == 0) ++ cnt, a[i] /= 2;
    }
    sort(a + 1, a + n + 1);
    cout << accumulate(a+1, a+n, 0ll) + (1ll<<cnt) * a[n] << endl;
}

signed main ()
{
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--; ) solve();
    return 0;
}

B. William the Vigilant

题意

给定长度为 \(n\) 的字符串,给定若干次操作(\(pos, c\)),每次操作把字符串第 \(pos\) 位替换为 \(c\) (字符串从1开始计数),问每次操作后至少再需要几次替换可以使此字符串没有子串 "\(abc\)" 。

分析

计算出字符串 \(abc\) 的次数,对于每一次替换,只能替换一次。

对于 \(pos\) 位,由于它要被替换,那么如果它是 \(abc\) 的一个,就要减去一次计数。

替换之后,检查是不是产生了一个 \(abc\) ,如果产生则增加一次计数。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
using namespace std;

int n, q;
string s;

bool check (int p)
{
    if (s[p] == 'a' && p + 2 < n && s.substr(p, 3) == "abc") return true;
    if (s[p] == 'b' && p - 1 >= 0 && p + 1 < n && s.substr(p-1, 3) == "abc") return true;
    if (s[p] == 'c' && p - 2 >= 0 && s.substr(p-2, 3) == "abc") return true;
    return false;
}

void solve ()
{
    int cnt = 0; cin >> n >> q;
    cin >> s;
    for (int i = 0; i < (int)s.size() - 2; i ++ )
        if (s.substr(i, 3) == "abc") ++ cnt;
    for (int i = 1; i <= q; i ++ )
    {
        int p; char chg; cin >> p >> chg;
        p -- ;
        if (check(p)) -- cnt;
        s[p] = chg;
        if (check(p)) ++ cnt;
        cout << cnt << endl;
    }
}

signed main ()
{
    cout.tie(0)->sync_with_stdio(0);
    // int _; for (cin >> _; _--; )
        solve();
    return 0;
}

C. Complex Market Analysis

题意

给定长度为 \(n\) 的序列 \(a\) 和正数 \(e\) 。问有多少序偶对 \((i, k)\) 满足:

\(a_i, a_{i + e}, a_{i + 2 * e}, \ldots a_{i + k * e}\) 的乘积为质数。

分析

质数最多只能有一个因子(除了 \(1\)) ,所以序偶 \((i, k)\) 一定要满足只有一个质数,其他都是 \(1\)

\(f(i)\) 表示 \(i\) 前面每隔 \(e\) 位的 \(1\) 的数量, \(g(i)\) 表示 \(i\) 后面每隔 \(e\) 位的 \(1\) 的数量。

那么就把间隔的问题变成了相邻的问题。

对于第 \(i\) 位,如果它是质数,那么它前面的 \(1\) ,每个都能取 \(g(i) + 1\) 。(取到 \(i\)\(i + e\)\(i + 2e\) \(\ldots\)

对于这一位本身也能取 \(g(i)\) 种,所以方案一共 \(f(i) \times (g(i) + 1) + g(i) = f(i) \times g(i) + f(i) + g(i)\) 种。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define rep(i, x, y) for(int i = x; i <= y; i++)
#define per(i, x, y) for(int i = x; i >= y; i--)
#define int long long
using namespace std;
const int N = 200010, M = 1000020;

int prime[M], cnt;
bool st[M];

void get_prime(int n)
{
    st[1] = true;
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) prime[cnt ++ ] = i;
        for (int j = 0; i * prime[j] <= n; j ++ )
        {
            st[i * prime[j]] = true;
            if (i % prime[j] == 0) break;
        }
    }
}

int f[N], g[N], a[N];

void solve ()
{
    int n, e, ret = 0; cin >> n >> e;
    rep(i, 1, n) f[i] = g[i] = 0;
    rep(i, 1, n) cin >> a[i];
    rep(i, 1, e) f[i] = (a[i] == 1);
    rep(i, e + 1, n)
    {
        f[i] = (a[i] == 1);
        if (a[i-e] == 1) f[i] += f[i-e];
    }
    per(i, n, n - e + 1) g[i] = (a[i] == 1);
    per(i, n - e, 1)
    {
        g[i] = (a[i] == 1);
        if (a[i+e] == 1) g[i] += g[i+e];
    }
    rep(i, 1, n) if (!st[a[i]]) ret = ret + f[i] * g[i] + f[i] + g[i];
    cout << ret << endl;
}

signed main ()
{
    get_prime(1000010);
    cout.tie(0)->sync_with_stdio(0);
    int _; for (cin >> _; _--; ) solve();
    return 0;
}

D. Social Network

题意

对于一张有 \(n\) 个点的图,有 \(d\) 个条件 \((i, j)\) ,表示 \(i\)\(j\) 需要在一个连通块。

在第 \(i\) 个条件时,你可以连 \(i\) 条边,但是要满足前面 \(i\) 个条件成立。

满足第 \(i\) 个条件后,问最大的可能的连通块大小。(题目是某个人认识的最大人数,要连通块大小 \(-1\)) 。

每个问题都是独立的,上一个答案需要连的边和这一个答案无关。

分析

并查集,假设前 \(i\) 个条件,有 \(k\) 个条件是已经满足的,那么可以自由连 \(k\) 条边,那就可以选择连通块大小最大的 \(k\) 个,把他们连起来。最开始只能选择一个连通块。

Code

/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define rep(i, x, y) for(int i = x; i <= y; i++)
using namespace std;
const int N = 200010;

int p[N], siz[N];

int f (int x) { return x == p[x] ? x : p[x] = f(p[x]); }

void solve ()
{
    int n, d, base = 1; cin >> n >> d;
    rep(i, 1, n) p[i] = i, siz[i] = 1;
    rep(i, 1, d)
    {
        int x, y, ret = 0; cin >> x >> y;
        x = f(x); y = f(y);
        if (x == y) base ++ ;
        else siz[y] += siz[x], p[x] = y;

        priority_queue<int> q;
        rep(j, 1, n) if (j == f(j)) q.push(siz[j]);
        rep(j, 1, base) ret += q.top(), q.pop();
        cout << ret - 1 << endl;
    }
}

signed main ()
{
    cout.tie(0)->sync_with_stdio(0);
    // int _; for (cin >> _; _--; )
        solve();
    return 0;
}
posted @ 2021-11-29 11:12  Horb7  阅读(61)  评论(0编辑  收藏  举报