Codeforces Round 861 (Div. 2)
Codeforces Round 861 (Div. 2)
Date: 03/29/2023
Link: Dashboard - Codeforces Round 861 (Div. 2) - Codeforces
A|Lucky Numbers
Brief: 从 \(l\) 到 \(r\) 的整数中找到任意一个最幸运的数。幸运度定义为一个数中最大数字和最小数字的差值。
Data: \(T\leq 1e4\), \(l,r\leq1e6\).
Solution: 【简单思维题】【构造】
暴力即可。最多 \(100\) 次可以找到幸运度为 \(9\) 的数。
题解给出当 \(r-l\geq 100\), 可以直接找后两位是 \(90\) 的数。
Review: -
State: AC.
B| Playing in a Casino
Brief: \(n\) 张牌,每张上 \(m\) 个数字。每人一张,每两人对决,胜者获得 \(\sum|a_i-b_i|\) 分(牌上对应数字相减)。问总共有多少分。
Data: \(n\cdot m\leq 3e5\).
Solution: 【简单思维题】
暴力即可。最多 \(100\) 次可以找到幸运度为 \(9\) 的数。
Solution: 【排序】【前缀和】
可以发现对于每张牌上的 \(m\) 个数字是互不干扰的(注意这个,有很多优化都基于此),因此只需考虑每张牌上对应的数即可。发现每个数对答案的贡献为他减去比他小的数的和,排序后前缀和计算即可。
Review: -
State: AC.
C| Unlucky Numbers
Brief: 题意同 \(A\), 但找幸运度最小的。
Data: \(T\leq 6e2\), \(l,r\leq1e18\).
Solution: 【构造】
显然没法暴力,注意并非有相等的数字幸运度就为 \(0\),因为并不一定的最大最小数字的差。
Observation: 答案一定可以是前 \(i\) 位和 \(l\) 或 \(r\) 相同,剩下的全取同一个数。原因:当某一位与 \(l\) 不相同且更大时,之后的数一定可以任意取而保证这个数不小于 \(l\)。\(r\) 同理。
因此,考虑到数据范围很小,只需要对 \(l\) 的每一位枚举比这一位大的数,再和 \(r\) 比较,如果合法,则判断能否更新答案。再对 \(r\) 做类似的操作。
Review: 脑子不太好用()。没想清楚就开始暴力,T了之后才意识到算法假了。
State: TLE => AC.
Code:
#include <iostream>
#include <cstdio>
using namespace std;
#define MAXN 20
int l[MAXN], lenl, r[MAXN], lenr;
int ans[MAXN], ans_luck = 10;
void Iput(int a[], int &len)
{
char c;
while ((c=getchar()) < '0' || c > '9');
a[++len] = c - '0';
while ((c=getchar()) >= '0' && c <= '9') a[++len] = c - '0';
}
int cmp(int a[], int b[], int len, int pos, int alt)
{
for (int i = 1 ; i < pos ; ++i)
{
if (a[i] < b[i]) return -1;
if (a[i] > b[i]) return 1;
}
for (int i = pos ; i <= len ; ++i)
{
if (a[i] < alt) return -1;
if (a[i] > alt) return 1;
}
return 0;
}
int calc_luck(int a[], int len)
{
int mina = 10, maxa = -1;
for (int i = 1 ; i <= len ; ++i)
{
mina = min(mina, a[i]);
maxa = max(maxa, a[i]);
}
return maxa - mina;
}
int calc_luck(int a[], int pos, int alt)
{
int mina = alt, maxa = alt;
for (int i = 1 ; i < pos ; ++i)
{
mina = min(mina, a[i]);
maxa = max(maxa, a[i]);
}
return maxa - mina;
}
void solve_l()
{
for (int i = 1 ; i <= lenl ; ++i)
for (int j = l[i] + 1 ; j <= 9 ; ++j)
if (cmp(r, l, lenl, i, j) != -1)
{
int cur_luck = calc_luck(l, i, j);
if (cur_luck < ans_luck)
{
ans_luck = cur_luck;
for (int k = 1 ; k < i ; ++k)
ans[k] = l[k];
for (int k = i ; k <= lenl ; ++k)
ans[k] = j;
}
}
}
void solve_r()
{
for (int i = 1 ; i <= lenr ; ++i)
for (int j = 0 ; j < r[i] ; ++j)
if (cmp(l, r, lenr, i, j) != 1)
{
int cur_luck = calc_luck(r, i, j);
if (cur_luck < ans_luck)
{
ans_luck = cur_luck;
for (int k = 1 ; k < i ; ++k)
ans[k] = r[k];
for (int k = i ; k <= lenr ; ++k)
ans[k] = j;
}
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
lenl = lenr = 0;
Iput(l, lenl);
Iput(r, lenr);
if (lenl == 1 && l[lenl] == 0) // Is that possible?
{
putchar('0');
putchar('\n');
continue;
}
if (lenl != lenr) // 长度不一致时输出 l 长度个 9 一定合法
{
for (int i = 1 ; i <= lenl ; ++i)
putchar('9');
putchar('\n');
continue;
}
int luck_l = calc_luck(l, lenl);
int luck_r = calc_luck(r, lenr);
if (luck_l < luck_r)
{
ans_luck = luck_l;
for (int k = 1 ; k <= lenl ; ++k)
ans[k] = l[k];
}
else
{
ans_luck = luck_r;
for (int k = 1 ; k <= lenr ; ++k)
ans[k] = r[k];
}
solve_l();
solve_r();
for (int i = 1 ; i <= lenl ; ++i)
putchar(ans[i] + '0');
putchar('\n');
}
return 0;
}
D| Petya, Petya, Petr, and Palindromes
Brief: 给出一个整数序列,对于所有长度为奇数 \(k\) 的子串,最少修改几个数使其成为回文,求和。
Data: \(n\leq 2e5, a_i\leq2e5\).
Solution: 【回文】【计数】
对于每一个数,考虑它会和谁比较。我们可以计算出对于 \(a_i\) 的区间 \([l, r]\),\(a_i\) 会和其中所有位置和 \(i\) 奇偶性相同位置的数比较。\(l\) 为对称中心在 \(i+1\) 时的对应点,\(r\) 为 \(a_i\) 在 \(k\) 区间最左端的对应点。另外,还有 \(l\) 和 \(r\) 的限制是长度为 \(k\) 的区间不超出数组两端。
反面考虑统计不用修改的数量,即比较结果是相同的数量。答案即是总比较数量 \((n - k + 1)\cdot(k - 1) / 2\) 减去比较结果是相同的数量。
因此只需要对于每个 \(i\), 找到对应的 \([l,r]\), 对于这个区间维护数组 bt[a][odd/even], 第一维是值域,第二维表明是奇数还是偶数位置的桶。每次答案减去即可。由于 \(l\) 和 \(r\) 每次的变动不超过 \(1\), 所以可以很快维护。
反面考虑不修改的,即对称后相等的。那么一个数会和它前后长度为 \(k\) 的区域(包含自己)中每间隔一个数比较一次。因此可以分奇偶考虑。对于奇(偶)数部分,滑动窗口,长度为 \((k+1)/2\), 统计和自身相等的数的个数的和。答案是总的比较次数即 \((n - k + 1)\cdot (k - 1) / 2\) 减去这个和。
Review: 感觉当时是题都没读清楚,以为马拉车…赛后终于理清思路。
State: - => AC.
Code:
#include Justanaaaaame
#include <iostream>
using namespace std;
#define MAXN 200010
int n, k;
int a[MAXN];
long long ans;
int bt[MAXN][2];
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> k;
ans = (n - k + 1LL) * (k - 1LL) / 2LL;
for (int i = 1 ; i <= n ; ++i)
cin >> a[i];
int curl = 0, curr = 0;
for (int i = 1 ; i < n - (k - 1) / 2 ; ++i)
{
int lc = max(i + 1, (k + 1) / 2);
int l = lc * 2 - i;
int rc = min(i + (k - 1) / 2, n - (k - 1) / 2);
int r = rc * 2 - i;
// cerr << i << ":l(" << l << "), r(" << r << ")\n";
while (curl > l)
{
--curl;
++bt[a[curl]][curl & 1];
}
while (curl < l)
{
--bt[a[curl]][curl & 1];
++curl;
}
while (curr < r)
{
++curr;
++bt[a[curr]][curr & 1];
}
while (curr > r)
{
--bt[a[curr]][curr & 1];
--curr;
}
ans -= bt[a[i]][i & 1];
}
cout << ans << endl;
return 0;
}
E|Minibuses on Venus
State: 咕咕咕……

浙公网安备 33010602011771号