Codeforces Round #694 (Div. 2)

A

  这个题目就是说有一个序列a,并且给我们一个除数x,我们可以对序列a相邻的两项进行合并(也就是用这两个数的和数来替换掉原来的两个数),我们要求出aix的最大值和最小值。
思路:
  最大值很显然就是对原来的序列不做任何的合并,这样原来序列中的所有数的贡献并不会被抵消所以max=i=1naix,最小值是要将ai所产生的贡献尽可能的抵消掉,但是我们只能将相邻的两项相加,所以要使最后的贡献最小,就是将所有的数都加起来保证能够尽可能大的抵消掉所有数对最后结果的贡献,min=aix

int n, m; std::cin >> n >> m; std::vector<int> a(n + 1); for (int i = 1; i <= n; i ++ ) std::cin >> a[i]; i64 ans = 0; for (int i = 1; i <= n; i ++ ) ans += a[i] / m, a[i] %= m; i64 sum = std::accumulate(all(a), 0ll); i64 mx = ans + sum / m + !(sum % m == 0); rep(i, 1, n + 1) ans += (a[i] > 0); std::cout << mx << " " << ans << "\n";

B

  题目就是给我们一个序列a每一次在这个序列a后面增加xaix,一直到ai不能整除x为止,求ai
思路:
  很显然每一次在序列后面加的数的和就是被分解的ai,所以我们只需要统计序列a中被分解次数最小的那个数的位置idx和次数cnt,最后求和的时候,在idx左边的所有数产生的贡献和就是0idx1ai(cnt+1),在idx1右边的所有数的贡献就是sumidxn1aicnt;

void solve() { int n, x; std::cin >> n >> x; std::vector<int> a(n); rep(i, 0, n) std::cin >> a[i]; i64 ans = 0; std::vector<int> cnt(n); rep(i, 0, n) { int t = a[i]; while (t % x == 0) { cnt[i] ++; t /= x; } } int idx = 0, mn = 1e9; rep(i, 0, n) if (mn > cnt[i]) idx = i, mn = cnt[i]; mn ++; rep(i, 0, n) if (i < idx) ans += 1ll * a[i] * (mn + 1); else ans += 1ll * a[i] * mn; std::cout << ans << "\n"; }

C

  题目就是说给n个人买礼物,给第i个人买的礼物只能是ki之前的礼物,但是所有的m个礼物最多只能够买一次,如果不能买礼物的话,可以给第ki个物品所对应的价格c[ki],让我们求出他给朋友准备礼物花的最少的钱是多少。
思路:
  很明显我们要让总钱数最小的话,就必须让本来对应的c[ki]大的收到ki之前的礼物,所以我们先将ki进行排序,将价格小的物品优先给序号靠后的人,由于每一个礼物只能买给一个人,所以我们可以用一个下标idx来记录当前送到了第几个礼物,当c[ki]<c[idx]的时候,我们就开始直接送钱,因为题目中保证了c1c2cm 所以这样的分配一定是最优的。

void solve() { int n, m; std::cin >> n >> m; std::vector<int> k(n), c(m); rep(i, 0, n) std::cin >> k[i]; rep(i, 0, m) std::cin >> c[i]; std::sort(all(k)); i64 ans = 0; int idx = 0; std::vector<bool> st(n); per(i, 0, n) if (c[k[i] - 1] > c[idx]) ans += c[idx ++ ]; else ans += c[k[i] - 1]; std::cout << ans << "\n"; }

D

  该题目告诉我们两个数x,y它们的lcm(x,y)gcd(x,y)如果是一个完全平方数的话,我们就称它们是相邻的。 现在给我们一个长度为n的数组a,每一秒数组中的每个元素ai都被数组中与当前值相邻的所有元素(包括其自身)的乘积所取代。让di是每一个ai的相邻的值,一个数组的美丽度被定义为max1indi。现在有q次询问,每次都会让我们求出来w秒后这个数组的美丽度是多少。


思路:
  看到lcm(x,y)gcd(x,y)是一个完全平方数,可以想着去推一下式子,因为lcm(x,y)=xygcd(x,y,所以可以将原式推导为xy(gcd(x,y))2 是一个完全平方数,所以可以写成(xygcd(x,y))2==x2当且仅当xy是完全平方数的时候该等式方才成立。那么问题就转化成了将xy分解质因数,其中每一个因子的幂次都可以被2整除也就是xy=p1k1p2k2pnkn,其中k1,k2,k3kn都是2的倍数。因此我们只需要记录zi=p1k1%2p2k2%2pnkn%2 ,如果zi==zj说明两数相乘的质因子的幂次都为偶数,是个完全平方数。
  用欧拉筛来得到每一个数的最小质因子

void Eular(int n) { prime[idx ++ ] = 2; minp[2] = 2; st[2] = true; for (int i = 3; i <= n; i += 2) { if (!st[i]) prime[idx ++ ] = i, minp[i] = i, st[i] = true; for (int j = 0; prime[j] * i <= n; j ++ ) { st[prime[j] * i] = true; minp[prime[j] * i] = prime[j]; if (i % prime[j] == 0) break; } } }

在我们得到zi的时候如果出现了偶数次幂,那么我们后面在判断完全平方数的时候还是会被分解掉,所以我们只需要在出现奇数次幂的时候在zi的基础上乘上一个pi1

void solve() { int n; std::cin >> n; std::vector<int> a(n + 1); rep(i, 1, n + 1) std::cin >> a[i]; std::map<int, int> mp; rep(i, 1, n + 1) { int val = a[i]; int z = 1; while (val > 1) { int p = minp[val]; int cnt = 0; while (val % p == 0) { cnt ++; val /= p; } if (cnt % 2 == 1) z *= p; } mp[z] ++; } // 找到匹配上的另一个数 int cnt0 = 0; for (auto &p : mp) cnt0 = std::max(cnt0, p.second); for (auto &p : mp) { if (p.first == 1 || p.second % 2 == 1) continue; mp[1] += p.second; mp[p.first] = 0; } int cnt1 = 0; for (auto &p : mp) cnt1 = std::max(cnt1, p.second); int m; std::cin >> m; while (m -- ) { int op;std::cin >> op; std::cout << (op == 0 ? cnt0 : cnt1) << "\n"; } }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16142900.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示