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;
}