Codeforces Round 885 (Div. 2)

Codeforces Round 885 (Div. 2)

A. Vika and Her Friends

题目大意

太长了 click

思路

可以手动模拟一下,可以发现当两个人的 x+y 值就行相同的就能抓到了

#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while (T--) { int n, m, k; cin >> n >> m >> k; bool flag = false; int a, b; cin >> a >> b; for (int i = 1; i <= k; i++) { int c, d; cin >> c >> d; if ((a + b - (c + d)) % 2 == 0) flag = true; } if (!flag) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }

B.Vika and the Bridge

题目大意

n 块木板排成一排,第 i 块木板的颜色是 ci,你站在第一块木板前面,需要跳跃到第 n 块木板后面,每一次只能跳相同颜色的木板。现在你可以更改一块木板的颜色,使得你每一次跳跃的距离(指两块木板中间部分,不计两端点)的最大值最小,请求出这个值。

思路

首先我们知道一个结论,当一个点到另一个与它相同颜色的点的距离是最大的,那么,我们只要在中间插上一个与其颜色相同的点就能让最大长度的除以 2 。

我们考虑维护最大距离 fmax 和次大距离 smax,最后统计 min{max{fmaxi2,smaxi}} 即可

int distance = i - last[a[i]] - 1; if (distance > fimax[a[i]]) { smax[a[i]] = fimax[a[i]]; fimax[a[i]] = distance; } else if (distance > smax[a[i]]) smax[a[i]] = distance; --------------------------------------- last[a[i]] = i; int ans = 1e9 + 7; for (int i = 1; i <= m; i++) ans = min(ans, max(smax[i], fimax[i] / 2));

C.Vika and Price Tags

题目大意

给定 n (1n1×105) 对整数 a,b (1a,b1×109),每次使 abb←∣ab,求是否能实现让所有的 a 在有限次同步操作后都变为 0

思路

这道题显然用到了“更相减损法”,既然是更相减损,那么就会想到词 gcd

对于 a,b(a>b) 的最大公因数 gcd(a,b), 有

gcd(a,b)=gcd(b,ab)

在更相减损法的过程中 gcd(a,b) 显然不变,最后使得 a=0 ,此时 gcd(a,b)b

最终满足题目序列的序列的是这样的

0 0 0 0
gcd(a1,b1) gcd(a2,b2) gcd(a3,b3) ...

我们只需要讨论所要的 gcd(ai,bi) 能不能同时出现。

对于满足条件的数对 (0,b) 在操作过程中的状态可能是 (0,b),(b,b),(b,0) ,并在三种状态中有序循环

考虑简化,对于数对 (a,b),在进行 k 此操作后可以形成 (0,x) 满足条件的数对,那么对于数对 (qa,qb) 可以在进行 k 次操作后,一定变成 (0,qx) ,在所有操作中 q 可以当成公因数提出

同理,数对 (a,b) 与 数对 (agcd(a,b),bgcd(a,b)) 等价

接下来用互质给数对 (a,b) 进行分类,当 ab 互质时,会有

a
b

如何证明以上就是我们所需的三种分类呢?

a=2k,b=2k+1

a 2k 2k+1 1 2k 2k1 1 2k2 ...
b 2k+1 1 2k 2k1 1 2k2 2k3 ...

发现数对 (a,b) 总是在给出的三种情况反复循环

以奇奇,奇偶开始同理

所以我们证明了,数列能否合法,只与其间数对的奇偶性有关。如果数对的奇偶性有且仅有唯一的一种,那么就能成立。

int work(int x, int y) { int gcc = gcd(x, y); x /= gcc, y /= gcc; if (x % 2 == 0) return 0; if (y % 2 == 0) return 1; return 2; } ------------------------------- for (int i = 1; i <= n; i++) { if (a[i] == 0 && b[i] == 0) continue; res = work(a[i], b[i]); if (res == 0) sum0 = 1; if (res == 1) sum1 = 1; if (res == 2) sum2 = 1; }

D.Vika and Bonuses

题目大意

T105 组数据。

每组数据给定 s,k (s,k109)

你需要维护一个计数器 C(初始为 0)并进行 k 次操作,每次操作形如二者之一:

  1. CC+s
  2. ss+smod10.

输出 k 次操作后 C 的最大值。

思路

对于每一次增加后的各位情况,我们可以手玩一下

这里假设 s=1

00,12,24,36,48,50,62,74,86,98

我们发现个位要么变成 0,要么就在 2486 这里循环。

s 个位数为 0 时,操作再多次也没用,为 5 时,显然操作一次就会变成 0 ,同理。

我们发现 2486 是一轮循环,且这轮循环后,s会增加 20 ,我们设进行 x 轮循环后答案为 y ,容易列出方程

y=(s+20x)(k4x)

y=80x2+(20k4s)x+sk

很容易看出一元二次方程的 a=80,b=(20k4s),c=sk

这里推一下极值点坐标

y=ax2+bx+c

y=a[x2+2b2ax+(b2a)2]+cab2(2a)2

y=a(x+b2a)2+cb24a

x+b2a

x=b2a,

x=5ks40

但这个数不一定是整数,所以我们要拿上取整合下取整计算答案并取 max, 但是我们这样只能计算单个个位数的情况,因此我们要在计算答案以前,枚举个位数,再对答案取 max

#include <bits./stdc++.h> using namespace std; typedef long long LL; LL s, k; LL work(LL s, LL k) { LL ans = s * k; LL x = max(min((5 * k - s) / 40, k / 4), 0ll); ans = max(ans, -80 * x * x + (20 * k - 4 * s) * x + s * k); x = min(x + 1, k / 4); ans = max(ans, -80 * x * x + (20 * k - 4 * s) * x + s * k); return ans; } LL solve() { cin >> s >> k; if (s % 10 == 0) return s * k; if (s % 10 == 5) return max(s * k, (s + 5) * (k - 1)); LL ans = s * k; if (s % 2) s += s % 10, k--; for (int i = 1; i <= 4; i++) { if (k <= 0) break; ans = max(ans, work(s, k)), s += s % 10, k--; } return ans; } int main() { LL t; cin >> t; while (t--) cout << solve() << endl; return 0; }

__EOF__

本文作者ljfyyds
本文链接https://www.cnblogs.com/ljfyyds/p/17599084.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   ljfyyds  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示