Codeforces Round 891 (Div. 3)

Codeforces Round 881 (Div. 3)

A.Array Coloring

题目大意

link

思路

简单判断数组和的奇偶性即可(小学数学)

#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while (t--) { int n; cin >> n; int sum = 0, x; for (int i = 1; i <= n; i++) { cin >> x; sum += x; } if (sum % 2 == 0) puts("YES"); else puts("NO"); } return 0; }

Maximum Rounding

题目大意

遍历一个数字的每一位,判断在哪一位四舍五入值最大。

思路

按照题意模拟即可(比赛时被 HACK 了)

#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while (t--) { string s; cin >> s; s = '0' + s; int lst = s.size() - 1; for (int i = s.size() - 1; i >= 0; i--) { if (s[i] >= '5') { for (int j = i; j <= lst; j++) s[j] = '0'; lst = i - 1; if (s[i - 1] != '9') s[i - 1] += 1; else { while (s[i - 1] != '9') s[i - 1] = '0', i--; s[i - 1]++; } } } if (s[0] != '0') cout << s << endl; else cout << s.substr(1) << endl; } return 0; }

C.Assembly via Minimums

题目大意

![image-20230808200812873](C:\Users\Jianfan Li\AppData\Roaming\Typora\typora-user-images\image-20230808200812873.png)

思路

假设 a 有序,对 b 也进行排序,这是不影响结果的。

a 中最小值为 x,则 x 在排序后的 b 中会连续出现 n1 次,设次小值为 x1 ,在排序后的 i 会出现 n2 次(除了 x 其他都是本身) ,以此类推,第 n1 个数为 x,第 n1+n2 个数为 x1 ...

#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 1e6 + 10; LL a[N], b[N]; int n; int main() { int t; cin >> t; while (t--) { int n; cin >> n; for (int i = 1; i <= n * (n - 1) / 2; i++) cin >> a[i]; sort(a + 1, a + n * (n - 1) / 2 + 1); int cnt = 0, idx = 0; for (int i = n - 1; i; i--) { cnt += i; b[++idx] = a[cnt]; } for (int i = 1; i < n; i++) cout << b[i] << ' '; cout << b[n - 1] << endl; } return 0; }

D - Strong Vertices

题目大意

![image-20230808201625409](C:\Users\Jianfan Li\AppData\Roaming\Typora\typora-user-images\image-20230808201625409.png)

思路

将题目中的式移向得

aubububv

aubu 最大时才会向其他所有顶点连边,所以只需要找最大 aubu 即可

#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 2e5 + 5; struct node { LL id, num; } a[N]; bool cmp(node a, node b) { return a.id < b.id; } bool cmp2(node a, node b) { return a.num > b.num; } int main() { int t; cin >> t; while (t--) { int n; cin >> n; LL maxx = -0x3f3f3f3f3f3f; for (int i = 1; i <= n; i++) cin >> a[i].num; for (int i = 1; i <= n; i++) { int x; cin >> x; a[i].num -= x; a[i].id = i; maxx = max(maxx, a[i].num); } sort(a + 1, a + n + 1, cmp2); int ans = 0; for (int i = 1; i <= n; i++) ans += (a[i].num == maxx); cout << ans << endl; sort(a + 1, ans + a + 1, cmp); for (int i = 1; i <= ans; i++) cout << a[i].id << ' '; cout << endl; } return 0; }

E - Power of Points

题目大意

给定 n 个数轴上的点,你需要依次选中每个点,计算选中该点的权值。

选中一个点后,将它和每一个点之间连一条线段(包括它自己),线段会覆盖两端点之间的整点一次(包括两个端点),权值定义为数轴上每个整点被覆盖的次数的和。

依次选中 1n 的每个点,计算权值并输出。

思路

题目给我们的是 被覆盖的次数和 实际上就是求线段的总长度

对于一条线段 [l,r] 如果 l<r 那么长度为 rl+1,反之为 lr+1,而 l,r 分别为 xi,s

所以易得线段总长为 i=1n(|xis|+1)=i=1n(|xis|)+n

问题来到如何快速求解以上式子,我们其实可以先拆分

(xix1)+(xix2)+...+(xi+1xi)+...+(xnxi)+n

把式子分成两部分

  1. (xix1)+(xix2)+...(xixi) 这个部分可以化为 i×xij=1ixj 这个不难维护,为前缀和。
  2. (xi+1xi)+...+(xnxi) 这个部分可以化为 j=i+1nxj(ni)×xi 这个就是后缀和维护

然后将两个式子拼起来即可。

void solve() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i].num, a[i].id = i; sort(a + 1, a + n + 1, cmp); for (int i = 1; i <= n; i++) f[i] = a[i].num + f[i - 1]; h[n + 1] = 0; for (int i = n; i >= 1; i--) h[i] = h[i + 1] + a[i].num; for (int i = 1; i <= n; i++) a[i].ans = a[i].num * (i - 1) - f[i - 1] + h[i + 1] - a[i].num * (n - i) + n; sort(a + 1, a + n + 1, cmp2); for (int i = 1; i <= n; i++) cout << a[i].ans << ' '; cout << endl; }

F - Sum and Product

题目大意

link

思路

考虑 aj=xai ,带入积的那个式子就是 (xai)×ai=y 也就是 (x×aiai2=y)

移向可得 ai2x×ai+y=0 ,这样就变成一个一元二次方程的一般形式了

运用公式得 ai=x±x24y2 不难想到 x24y 小于 0 时无解,若得出来的两个解的和不为 x ,积不为 y 那么也输出 0

算可能性易得用乘法原理,为 cntai×cntaj cnt表示值得出现次数

ai=ajC2aicntai×cntai12

LL solve(LL b, LL c) { LL a1, a2; LL delta = b * b - 4 * c; if (delta < 0) return 0; a1 = (b - sqrt(delta)) / 2; a2 = (b + sqrt(delta)) / 2; if (a1 + a2 != b || a1 * a2 != c) return 0; if (delta == 0) return (LL)mp[a1] * (mp[a1] - 1) / 2; return (LL)mp[a1] * mp[a2]; }

G题

这道题首先我们肯定就是要添加不是最小生成树上的边

既然是添加,那么就一定有一些条件

1.边权大于最小生成树的树边的最大值

原因即为:

如果添加的边等于树边的最大值,那么最小生成树不唯一

如果小于,那么最小生成树就不是给定的那棵

然后考虑所有满足条件的图的数量

对于两个集合 a,b 其中 ab 是有一条边的,那么考虑将一个集合上的点跑到另外一个集合上的点去

那么显然这个跑的路径是大于树边最大值,而且这些边的总数显然为 sizasizb1 ,其中 siz

意思为某个集合的节点数量, 1 表示 ab这条边不能连,而这些边权大小范围显然是 sw+1 , w表示树边的权值,原来是 [w+1,s] 中的个数,但是还有一个不加边,所以加上1

最大值,那么两个集合之间的可能性易得:sw+1siza×sizb1

这个可能不太好理解

我们举个例子,比如有n棵骰子,每个骰子落地后朝上的那一面大小范围为 16,那么这些骰子一起掉落

可能性为 (6n)

这其实就是多个乘法原理的组合

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10, mod = 998244353; ll fa[N]; //并查集 ll siz[N]; int n, s; struct node { int u, v, w; } a[N]; ll find(ll x) //并查集查找 { if (fa[x] == x) return x; return fa[x] = find(fa[x]); } bool cmp(node a, node b) { return a.w < b.w; } ll qpow(ll a, ll k) //快速幂 { ll res = 1; while (k) { if (k & 1) res = res * a % mod; a = a * a % mod; k >>= 1; } return res; } void solve() { cin >> n >> s; for (int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1; for (int i = 1; i < n; i++) { int u, v, w; cin >> u >> v >> w; a[i] = {u, v, w}; } sort(a + 1, a + n, cmp); ll ans = 1; for (int i = 1; i < n; i++) { int fx = find(a[i].u), fy = find(a[i].v); ans = ans * qpow(s - a[i].w + 1, siz[fx] * siz[fy] - 1) % mod; fa[fx] = fy; siz[fy] += siz[fx]; } cout << ans % mod << endl; } int main() { int t; cin >> t; while (t--) solve(); return 0; }

__EOF__

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