H. GCD is Greater

2024-04-12 02:52
文章标签 gcd greater

本文主要是介绍H. GCD is Greater,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

H. GCD is Greater

题意

  给定一个长度为 n n n的数组 a a a,先手选择 [ 2 , n − 2 ] [2,n-2] [2,n2]个数并计算所选择数的gcd,后手选择剩下的数,并计算剩下所有的数按位与的结果,再加上给定的 x x x,如果先手的结果大于后手,则先手赢,否则后手赢。找出先手必胜的方案,或输出先手不可能获胜。

分析

  首先贪心地想到,若想gcd大,选择的数的数量越小越好,即只选择两个数,因为再选择别的数gcd不会再增加,而不会让结果更优。
  再考虑到后手的计算过程为剩下的数按位与,那么考虑每一位的最终结果,统计每一位在数组中出现了多少次。对于每一位,此时有三种可能,令先手选择的两个数的下标为 x 1 x_{1} x1 x 2 x_{2} x2

  • x 1 x_{1} x1 x 2 x_{2} x2中有一个数在该位为1
  • x 1 x_{1} x1 x 2 x_{2} x2在该位的值都是1
  • x 1 x_{1} x1 x 2 x_{2} x2在该位的值都是0

对于上述三种情况,当该位为 1 1 1的数量 − ( x 1 -(x_{1} (x1 x 2 x_{2} x2在该位为 1 1 1的数量 ) = n − 2 )=n-2 )=n2,则后手计算的结果中这一位必定是 1 1 1,否则必定是 0 0 0,那么我们可以找到这些特殊点,即该位为 1 1 1的数量为 n n n n − 1 n-1 n1 n − 2 n-2 n2时, a i a_{i} ai在该位非 1 1 1,那么当我们选或不选它们对结果是有影响的。该集合大小为 2 l o g ( m a x ( a i ) ) 2log(max(a_{i})) 2log(max(ai))。然后考虑除了上述情况的其他情况,根据贪心想法,肯定是gcd越大越好,那么我们可以存下每个数以及其约数出现次数的和,然后从大到小枚举gcd的大小,暴力判断即可,只需要判断能取到的最大gcd即可,其他的必然不会比最大的更优。
  对于会影响按位与的数,固定一个有影响的数,然后枚举另一个数,再暴力判断是否符合条件即可,时间复杂度 O ( n ( ( l o g ( m a x a i ) ) 2 + l o g ( m a x a i ) l o g V ) ) O(n((log(maxa_{i}))^{2}+log(maxa_{i})logV)) O(n((log(maxai))2+log(maxai)logV)) l o g V logV logV为计算gcd的复杂度

AC代码

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
vector<int> p[400010];
void init() {for (int i = 1; i <= 400000; i++) {for (int j = i; j <= 400000; j += i) {p[j].emplace_back(i);}}
}
LL gcd(LL a, LL b) {return b == 0 ? a : gcd(b, a % b);
}
void Solve() {int n, x;cin >> n >> x;vector<int> a(n + 1);for (int i = 1; i <= n; i++) {cin >> a[i];}int maxx = *max_element(a.begin() + 1, a.end());int L = __lg(maxx);vector<int> cnt(L + 1);vector<int> cnt1(maxx + 1);vector<int> z;for (int i = 1; i <= n; i++) {for (int j = 0; j <= L; j++) {if (a[i] >> j & 1) {cnt[j]++;}}}vector<bool> vis(n + 1);for (int j = 0; j <= L; j++) {if (cnt[j] < n - 2) {continue;}for (int i = 1; i <= n; i++) {if (!(a[i] >> j & 1)) {z.emplace_back(i);vis[i] = true;}}}for (int i = 1; i <= n; i++) {if (!vis[i]) {int sz1 = p[a[i]].size();for (int j = 0; j < sz1; j++) {cnt1[p[a[i]][j]]++;}}}vector<int> q;for (int i = maxx; i >= 1; i--) {if (cnt1[i] < 2) {continue;}for (int j = 1; j <= n && q.size() < 2; j++) {if (a[j] % i == 0 && !vis[j]) {q.emplace_back(j);}}int g = gcd(a[q[0]], a[q[1]]);int sum = 0;for (int j = 0; j <= L; j++) {int num = 0;if (a[q[0]] >> j & 1) {num++;}if (a[q[1]] >> j & 1) {num++;}if (cnt[j] - num == n - 2) {sum |= (1 << j);}}if (sum + x < g) {cout << "YES\n";cout << "2 " << a[q[0]] << " " << a[q[1]] << '\n';cout << n - 2 << " ";for (int j = 1; j <= n; j++) {if (j != q[0] && j != q[1]) {cout << a[j] << " ";}}cout << '\n';return;}break;}sort(z.begin(), z.end());z.erase(unique(z.begin(), z.end()), z.end());int sz = z.size();for (int i = 0; i < sz; i++) {for (int j = 1; j <= n; j++) {if (z[i] == j) {continue;}int sum = 0;for (int k = 0; k <= L; k++) {int num = 0;if (a[j] >> k & 1) {num++;}if (a[z[i]] >> k & 1) {num++;}if (cnt[k] - num == n - 2) {sum |= (1 << k);}}int g = gcd(a[j], a[z[i]]);if (sum + x < g) {cout << "YES\n";cout << "2 " << a[j] << " " << a[z[i]] << '\n';cout << n - 2 << " ";for (int k = 1; k <= n; k++) {if (k != z[i] && k != j) {cout << a[k] << " ";}}cout << '\n';return;}}}cout << "NO\n";
}
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);init();int T;cin >> T;while (T--) {Solve();}return 0;
}

这篇关于H. GCD is Greater的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/895907

相关文章

leetcode#496. Next Greater Element I

题目 You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1’s elements in the corresponding places of nums

每日一题~cf 970 div3 (A思维,B小模拟,C二分,D排列数建图成环,E 26个字母暴力+前缀和,F 逆元,G 数论gcd )

A 题意: 有 a 个1 ,b 个2.问是否能将这些数划分为两个数值相等的集合。 输出 YES 或者 NO —————— 问题等价于 将数组 分成两个数值相同的数组。所以sum 应该是偶数。也就是说 1 的个数是偶数。在i1的个数是偶数的情况下,将 2 分成两份,如果2 的个数是偶数,OK。如果是奇数那么需要1来补齐,如果1 的个数大于等于2那么可以补齐。(1 的个数是偶数,需要2个1来补齐,剩下

iOS——GCD再学习

GCD 使用GCD好处,具体如下: GCD 可用于多核的并行运算;GCD 会自动利用更多的 CPU 内核(比如双核、四核);GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程);程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码。 任务与队列 概念 **任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码。**在 GCD 中是放在 block 中

GCD常用函数拾遗

目录 dispatch_block_t监听block执行结束dispatch_block_waitdispatch_block_notify 撤销block总结参考 这几天偶尔又回顾了下GCD的知识。之前我一直以为自己对于GCD已经大体有个整体掌握了,却发现仍还有一些知识点的遗漏。于是写在这里,算是对之前GCD常用函数文章的补充。 dispatch_block_t 在GCD中

环上k划分的和的gcd的最大值【gcd基本性质的利用】

今早看到的题,想了下会做了,但是觉得这题挺有意思的,于是打算写一下做法。本题利用了gcd的基本性质:更相减损法以及结合律,平时做gcd的题基本没用到过这两性质,而本题对这性质进行了充分利用。 思路: 首先我们考虑给一个序列,我们该怎么做。 令 fn=∑ni=1ai f_n=\sum_{i=1}^n a_i。 我们考虑序列的一个 k+1 k+1划分 fx1,fx2−fx1,fx3−fx2

猫猫学iOS(五十一)多线程网络之GCD下载合并图片_队列组的使用

猫猫分享,必须精品 原创文章,欢迎转载。转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 合并图片(图片水印)第一种方法 效果 实现: 思路: 1.分别下载2张图片:大图片、LOGO 2.合并2张图片 3.显示到一个imageView身上 // 异步下载dispatch_async(dis

猫猫学iOS(五十)多线程网络之GCD简单介绍(任务,队列)

猫猫分享,必须精品 原创文章,欢迎转载。转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents GCD简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方

iOS面试:GCD的队列(dispatch_queue_t)分哪两种类型?

在 iOS 开发中,Grand Central Dispatch (GCD) 提供了强大的并发执行任务的能力。dispatch_queue_t 是 GCD 中的一个重要对象,用于管理和调度要执行的任务。GCD 的队列主要可以分为两种类型: 1. 串行队列(Serial Queues) 串行队列确保在同一时间只执行一个任务。任务按照它们被添加的顺序逐个执行。这种队列适用于需要操作共享资源的场景,

GCD部分用法

1,用gcd延迟执行任务 如果我们需要某个方法在一段时间后执行,那么我们常常会调用这样的方法 - (void)viewDidLoad{     [super viewDidLoad];     [self performSelector:@selector(printString:) withObject:@"Grand Central Dispatch" afterDel

学习GCD的一些基本用法

1.使用dispatch_get_global_queue创建一个并行队列,系统默认给我们提供了四种优先级的global Queue,每一个Queue都是一个单例 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_get_global_queue创建并